diff options
| author | srdusr <trevorgray@srdusr.com> | 2025-09-24 05:25:39 +0200 |
|---|---|---|
| committer | srdusr <trevorgray@srdusr.com> | 2025-09-24 05:25:39 +0200 |
| commit | a1627ac743289e768b138f1a60753a62e0869cc4 (patch) | |
| tree | 92ab373442943f621bb26b3b284bb1da90e2923a /unix | |
| parent | fdb0eb921205c34fb6ff5728727a097767ffae5a (diff) | |
| download | dotfiles-a1627ac743289e768b138f1a60753a62e0869cc4.tar.gz dotfiles-a1627ac743289e768b138f1a60753a62e0869cc4.zip | |
Update/Overhaul
Diffstat (limited to 'unix')
41 files changed, 0 insertions, 4765 deletions
diff --git a/unix/dev/.gitkeep b/unix/dev/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/unix/dev/.gitkeep +++ /dev/null diff --git a/unix/media/.gitkeep b/unix/media/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/unix/media/.gitkeep +++ /dev/null diff --git a/unix/net/.gitkeep b/unix/net/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/unix/net/.gitkeep +++ /dev/null diff --git a/unix/sec/.gitkeep b/unix/sec/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/unix/sec/.gitkeep +++ /dev/null diff --git a/unix/sys/battery_alert.sh b/unix/sys/battery_alert.sh deleted file mode 100755 index 47fa556..0000000 --- a/unix/sys/battery_alert.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh - -# Send a notification if the laptop battery is either low or is fully charged. - -# Battery percentage at which to notify -WARNING_LEVEL=78 -CRITICAL_LEVEL=5 -BATTERY_DISCHARGING=$(acpi -b | grep "Battery 0" | grep -c "Discharging") -BATTERY_LEVEL=$(acpi -b | grep "Battery 0" | grep -P -o '[0-9]+(?=%)') - -# Use files to store whether we've shown a notification or not (to prevent multiple notifications) -FULL_FILE=/tmp/batteryfull -EMPTY_FILE=/tmp/batteryempty -CRITICAL_FILE=/tmp/batterycritical - -# Reset notifications if the computer is charging/discharging -if [ "$BATTERY_DISCHARGING" -eq 1 ]; then - # Battery is discharging - if [ -f "$FULL_FILE" ]; then - command rm "$FULL_FILE" - fi - if [ "$BATTERY_LEVEL" -le "$WARNING_LEVEL" ] && [ ! -f "$EMPTY_FILE" ]; then - notify-send "Low Battery" "${BATTERY_LEVEL}% of battery remaining." -u critical -i "battery-low-symbolic" -r 9991 - touch "$EMPTY_FILE" - fi - if [ "$BATTERY_LEVEL" -le "$CRITICAL_LEVEL" ] && [ ! -f "$CRITICAL_FILE" ]; then - notify-send "Battery Critical" "The computer will shut down soon." -u critical -i "battery-caution-symbolic" -r 9991 - touch "$CRITICAL_FILE" - fi -elif [ "$BATTERY_DISCHARGING" -eq 0 ]; then - # Battery is charging - if [ "$BATTERY_LEVEL" -gt 99 ] && [ ! -f "$FULL_FILE" ]; then - notify-send "Battery Charged" "Battery is fully charged." -i "battery-full-symbolic" -r 9991 - touch "$FULL_FILE" - fi - # Reset empty/critical notifications when charging begins - if [ -f "$EMPTY_FILE" ]; then - command rm "$EMPTY_FILE" - fi - if [ -f "$CRITICAL_FILE" ]; then - command rm "$CRITICAL_FILE" - fi -fi diff --git a/unix/sys/gsettings.sh b/unix/sys/gsettings.sh deleted file mode 100755 index 9054344..0000000 --- a/unix/sys/gsettings.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# Disable screen lock -gsettings set org.gnome.desktop.screensaver lock-enabled false -gsettings set org.gnome.desktop.session idle-delay 0 - -# Mutter Overlay Key -gsettings set org.gnome.mutter overlay-key '' - -# Disable update notification -#gsettings set org.gnome.software download-updates false -#gsettings set com.ubuntu.update-notifier no-show-notifications true -#sudo rm /etc/xdg/autostart/upg-notifier-autostart.desktop - -#sudo mv /etc/xdg/autostart/update-notifier.desktop /etc/xdg/autostart/update-notifier.desktop.old -#sudo mv /etc/xdg/autostart/gnome-software-service.desktop /etc/xdg/autostart/gnome-software-service.desktop.old - -# Custom Keybinding Names -gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "['/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/']" - -# Custom Keybinding 0 -gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ binding "<Alt>T" -gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ command "scratchpad" -gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ name "scratchpad" - -# Disable keyboard plugin -gsettings set org.gnome.settings-daemon.plugins.keyboard active false - -# Prefer dark mode -gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' - -# Default terminal -gsettings set org.cinnamon.desktop.default-applications.terminal exec wezterm - -# Disable screensaver -gsettings set org.gnome.desktop.session idle-delay 0 -gsettings set org.gnome.desktop.screensaver lock-enabled false - -# Hack -#gsettings set org.gnome.desktop.app-folders folder-children "['Red', 'SysAdmin', 'Blue']" diff --git a/unix/sys/keep_guest_awake.sh b/unix/sys/keep_guest_awake.sh deleted file mode 100755 index 13d839b..0000000 --- a/unix/sys/keep_guest_awake.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash - -# Host-side script to keep QEMU guest display awake without triggering anything -# and handle Windows key logic (disable it in the guest, map Caps Lock to Windows key). - -MONITOR_SOCKET_DIR="$HOME/machines/vm" -QEMU_CLASS="qemu-system-x86_64" -SEND_CMD_MONITOR="sendkey f15" -SEND_CMD_XDO="key --clearmodifiers F15" -DISABLE_WINDOWS_KEY_CMD="sendkey meta_l NoSymbol" # Using ctrl_l as a placeholder -CAPS_LOCK_CMD="sendkey meta_l" # Remapped Caps Lock to Super_L (Windows key) - -## Function to disable the Windows key and remap Caps Lock to Super_L -#disable_windows_key_and_remap_caps_lock() { -# shopt -s nullglob -# sockets=("$MONITOR_SOCKET_DIR"/*.socket) -# shopt -u nullglob -# -# for socket in "${sockets[@]}"; do -# # Get VM name from socket file -# VM_NAME=$(basename "$socket" .socket) -# VM_NAME=${VM_NAME%-serial} -# -# # Send QMP command to disable Windows key (Super_L key press/remap) -# qmp_command='{"execute": "device_key_press", "arguments": {"dev": "virtio-keyboard-pci", "key": "capslock"}}' -# echo "$qmp_command" | socat - "UNIX-CONNECT:$socket" >/dev/null -# -# # Send QMP command to remap Caps Lock to Super_L (Windows key) -# qmp_command='{"execute": "guest-execute", "arguments": {"path": "/usr/bin/xmodmap", "arg": ["-e", "keycode 66 = Super_L"]}}' -# echo "$qmp_command" | socat - "UNIX-CONNECT:$socket" >/dev/null -# -# # Optional: Disable Super_L key (Windows key) -# qmp_command='{"execute": "guest-execute", "arguments": {"path": "/usr/bin/xmodmap", "arg": ["-e", "keycode 133 = NoSymbol"]}}' -# echo "$qmp_command" | socat - "UNIX-CONNECT:$socket" >/dev/null -# done -#} - -# Function to keep the guest display awake by sending F15 key press -keep_guest_display_awake() { - shopt -s nullglob - sockets=("$MONITOR_SOCKET_DIR"/*.socket) - shopt -u nullglob - - if [ ${#sockets[@]} -eq 0 ]; then - sleep 30 - return - fi - - focused_qemu=false - - if command -v xdotool >/dev/null 2>&1; then - active_win_id=$(xdotool getwindowfocus 2>/dev/null) - if [ "$active_win_id" != "" ]; then - active_class=$(xdotool getwindowclassname "$active_win_id" 2>/dev/null) - if [[ "$active_class" == "$QEMU_CLASS" ]]; then - focused_qemu=true - fi - fi - fi - - if "$focused_qemu"; then - # QEMU is focused â send F15 via xdotool - #xdotool "$SEND_CMD_XDO" - echo "" - - else - # QEMU is not focused â send F15 via monitor - for socket in "${sockets[@]}"; do - echo "$SEND_CMD_MONITOR" | socat - "UNIX-CONNECT:$socket" - done - fi -} - -# Main loop -while true; do - # Handle Windows key remapping and Caps Lock disablement - #disable_windows_key_and_remap_caps_lock - - # Keep the guest display awake - keep_guest_display_awake - - # Sleep before next cycle - sleep 30 -done diff --git a/unix/sys/low-bat-notifier b/unix/sys/low-bat-notifier deleted file mode 100755 index a67b25d..0000000 --- a/unix/sys/low-bat-notifier +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash - -### VARIABLES - -POLL_INTERVAL=120 # seconds at which to check battery level -LAST_NOTIFIED=-1 # track last notified battery percentage to avoid repeated notifications - -# If BAT0 doesn't work for you, check available devices with: -# $ ls -1 /sys/class/power_supply/ -BAT_PATH=/sys/class/power_supply/BAT0 -BAT_STAT=$BAT_PATH/status - -if [[ -f $BAT_PATH/charge_full ]]; then - BAT_FULL=$BAT_PATH/charge_full - BAT_NOW=$BAT_PATH/charge_now -elif [[ -f $BAT_PATH/energy_full ]]; then - BAT_FULL=$BAT_PATH/energy_full - BAT_NOW=$BAT_PATH/energy_now -else - exit -fi - -kill_running() { - local mypid=$$ - local pids - mapfile -t pids < <(pgrep -f "${0##*/}") - - for pid in "${pids[@]}"; do - if [[ $pid -ne $mypid ]]; then - kill "$pid" - sleep 1 - fi - done -} - -get_battery_icon() { - local percent=$1 - if ((percent > 80)); then - echo "đ" # Full battery - elif ((percent > 60)); then - echo "đ" # High battery - elif ((percent > 40)); then - echo "đ" # Medium battery - elif ((percent > 20)); then - echo "đĒĢ" # Low battery - else - echo "â ī¸" # Critical battery - fi -} - -# Run only if battery is detected -if ls -1qA /sys/class/power_supply/ | grep -q BAT; then - - kill_running - - while true; do - bf=$(cat "$BAT_FULL") - bn=$(cat "$BAT_NOW") - bs=$(cat "$BAT_STAT") - - bat_percent=$((100 * $bn / $bf)) - bat_icon=$(get_battery_icon "$bat_percent") - - # Notify only at exact levels: 20%, 15%, and 10% - if [[ ($bat_percent -eq 20 || $bat_percent -eq 15 || $bat_percent -eq 10) && "$bs" = "Discharging" && $bat_percent -ne $LAST_NOTIFIED ]]; then - notify-send --urgency=critical "$bat_icon $bat_percent% : $([[ $bat_percent -eq 10 ]] && echo 'Critical Battery! Shutting down in 1 minute...' || echo 'Low Battery!')" - LAST_NOTIFIED=$bat_percent - - if [[ $bat_percent -eq 10 ]]; then - sleep 60 - shutdown now - fi - elif [[ "$bs" = "Charging" ]]; then - LAST_NOTIFIED=-1 - fi - - sleep "$POLL_INTERVAL" - done -fi diff --git a/unix/sys/session_manager.sh b/unix/sys/session_manager.sh deleted file mode 100755 index b6a6b03..0000000 --- a/unix/sys/session_manager.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/sh - -cd ~ - -# Default session to be executed -unset DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS - -session="" - -# Function to display and start the selected session -display() { - # Default list of sessions in priority order - default_sessions=("Hyprland" "bspwm" "sway") - - # Check conditions and set session command - if [ "$DISPLAY" = "" ] && [ "$XDG_VTNR" -eq 1 ]; then - if [ -f ~/.session ]; then - session=$(cat ~/.session) - rm ~/.session # Remove the session file after reading - fi - - if [ "$session" != "" ]; then - case "$session" in - bspwm ) - export XDG_SESSION_TYPE="x11" - session="startx /usr/bin/bspwm" - ;; - Hyprland | sway) - session="dbus-launch --sh-syntax --exit-with-session $session" - ;; - *) - echo "Session $session is not supported." - session="" - ;; - esac - else - # Iterate through default sessions to find a suitable one - for wm in "${default_sessions[@]}"; do - if command -v "$wm" >/dev/null 2>&1; then - case "$wm" in - bspwm ) - export XDG_SESSION_TYPE="x11" - session="startx /usr/bin/$wm" - break - ;; - Hyprland | sway) - session="dbus-launch --sh-syntax --exit-with-session $wm >/dev/null 2>&1 && exit" - #show_animation.sh - clear - break - ;; - esac - fi - done - fi - - # Execute the session command if session is set - if [ "$session" != "" ]; then - #echo "Starting session: $session" - eval "$session" - else - echo "No suitable window manager found or conditions not met." - fi - fi -} - -# Main function -main() { - display -} - -main "$@" diff --git a/unix/sys/shutdown_watchdog b/unix/sys/shutdown_watchdog deleted file mode 100755 index 79bc7bf..0000000 --- a/unix/sys/shutdown_watchdog +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -LOGFILE="/tmp/shutdown_watchdog.log" - -while true; do - echo "--- $(date) ---" >> "$LOGFILE" - uptime >> "$LOGFILE" - sensors >> "$LOGFILE" 2>/dev/null - acpi -V >> "$LOGFILE" 2>/dev/null - sleep 10 -done diff --git a/unix/utils/backlight_default.sh b/unix/utils/backlight_default.sh deleted file mode 100755 index b79e680..0000000 --- a/unix/utils/backlight_default.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -set -e - -backlight_sys_dir="/sys/class/backlight/intel_backlight" - -read -r max_brightness < "${backlight_sys_dir}/max_brightness" -read -r curr_brightness < "${backlight_sys_dir}/brightness" - -if ! groups | grep -q backlight; then - echo "User is not in the backlight group" - exit 1 -fi - -if [ "$#" -eq 0 ] ; then - # set to half that of 'max_brightness' - echo $((max_brightness / 2)) > "$backlight_sys_dir"/brightness - exit 0 -fi - -case "$1" in - up) increment="+ 10" ;; - down) increment="- 10" ;; - *) exit 1 ;; -esac - -new_brightness=$(($curr_brightness $increment)) - -if $((new_brightness < 1)) || $((new_brightness > $max_brightness)); then - exit 1 -else - echo "$new_brightness" > "$backlight_sys_dir"/brightness -fi diff --git a/unix/utils/colors.sh b/unix/utils/colors.sh deleted file mode 100755 index fc1c10c..0000000 --- a/unix/utils/colors.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash -colors=$@ -for (( n=0; n < $colors; n++ )) do - printf " [%d] $(tput setaf $n)%s$(tput sgr0)" $n "Hello World! -" -done -PADDING='Padding' - -main() { - local xterm_start=0 \ - xterm_width=8 \ - xterm_height=2 - - local cube_start=$((xterm_start + xterm_width * xterm_height)) \ - cube_width=6 \ - cube_height=$((6 * 6)) - - local greys_start=$((cube_start + cube_width * cube_height)) \ - greys_width=8 \ - greys_height=3 - - color_block $xterm_start $xterm_width $xterm_height - color_block $cube_start $cube_width $cube_height use_padding - color_block $greys_start $greys_width $greys_height - echo -} - -color_block() { - local start=$1 width=$2 height=$3 use_padding=$4 - local max s color_nums colors - - max=$((start + width * height - 1)) - - echo - for s in $(seq $start $width $max); do - color_nums=$(seq $s $((s + width - 1))) - colors="${use_padding:+$PADDING }${color_nums}${use_padding:+ $PADDING}" - - printf '%s%s %s%s\n' \ - "$(fg_bars $colors)" $ansi_reset \ - "$(bg_bars $colors)" $ansi_reset - done -} - -fg_bars() { - for color in $@; do - color_bar ansi_fg $color '' - done -} - -bg_bars() { - for color in $@; do - color_bar ansi_bg $color ' ' - done -} - -color_bar() { - local ansi=$1 color=$2 trail=$3 - - if [ "$color" == $PADDING ]; then - printf '%s %s' $ansi_reset "$trail" - else - local color_seq=$($ansi $color) - printf '%s %03d%s' $color_seq $color "$trail" - fi -} - -ansi_reset=$'\033[0m' - -ansi_fg() { - printf '\033[38;5;%dm' $1 -} - -ansi_bg() { - printf '\033[48;5;%dm' $1 -} - -main diff --git a/unix/utils/cryptocheck b/unix/utils/cryptocheck deleted file mode 100755 index 02ba42d..0000000 --- a/unix/utils/cryptocheck +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash -if [ ! -d ~/.cache/crypto ]; then - mkdir ~/.cache/crypto -fi -ticker=(BTC ETH ADA DOT SOL XMR) - -for currency in "${ticker[@]}"; do - echo "$currency" -done | while read coin - do - price=$(curl rate.sx/1$coin) - if [ $coin = "BTC" ]; then - icon=ķ° - elif [ $coin = "ETH" ]; then - icon=ķ°ĄĒ - elif [ $coin = "ADA" ]; then - icon=ķ°¨ - elif [ $coin = "DOT" ]; then - icon=ķ° - elif [ $coin = "SOL" ]; then - icon=ķ° - elif [ $coin = "XMR" ]; then - icon=ķ°´ - fi - - echo "$icon $coin: $price" > ~/.cache/crypto/$coin - - done - -date > ~/.cache/crypto/time - diff --git a/unix/utils/cryptonotify b/unix/utils/cryptonotify deleted file mode 100755 index 47883c3..0000000 --- a/unix/utils/cryptonotify +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -source cryptocheck -Output= -for file in ~/.cache/crypto/* -do - if [ ! -z "$Output" ]; then - if [ ! $(basename $file) = "time" ]; then - Output="$Output\n$(cat $file)" - fi - else - if [ ! $(basename $file) = "time" ]; then - Output="$Output$(cat $file)" - fi - fi - -done - -Output="$Output\n$(cat ~/.cache/crypto/time)" -notify-send "Crypto Prices" "$Output" diff --git a/unix/utils/disable_meta_key_guest.sh b/unix/utils/disable_meta_key_guest.sh deleted file mode 100755 index acbbdf5..0000000 --- a/unix/utils/disable_meta_key_guest.sh +++ /dev/null @@ -1,94 +0,0 @@ -ain "$@" -#!/usr/bin/env bash - -# Function to find the QEMU monitor socket dynamically and extract the VM name -get_socket_path() { - local socket_dir="$HOME/machines/vm" # Directory where your sockets are stored - local socket_file=$(find "$socket_dir" -type s -name "*-monitor.socket" | head -n 1) - - echo "[DEBUG] Found socket file: $socket_file" # Debugging line to check the socket file - - if [[ -z "$socket_file" ]]; then - echo "Error: No QEMU monitor socket found in $socket_dir." >&2 - exit 1 - fi - - # Extract the VM name from the socket file name - local vm_name=$(basename "$socket_file" -monitor.socket) - echo "[DEBUG] VM name detected: $vm_name" # Debugging line to check VM name - - echo "$socket_file" # Return the full socket path - echo "$vm_name" # Return the VM name -} - -# Function to check if sendkeys.awk is in the user's PATH or fall back to specific directories -find_sendkeys_awk() { - # Check if sendkeys.awk is in the user's PATH - if command -v sendkeys.awk &>/dev/null; then - echo "$(command -v sendkeys.awk)" - return 0 - fi - - # Otherwise, check in specific fallback directories - local possible_paths=( - "$HOME/.scripts/env/linux/utils/sendkeys.awk" - "$HOME/.scripts/sendkeys.awk" - ) - - for path in "${possible_paths[@]}"; do - if [[ -f "$path" ]]; then - echo "$path" - return 0 - fi - done - - echo "sendkeys.awk not found in the user's PATH or known directories." >&2 - exit 1 -} - -send_guest_command() { - local cmd="$1" - local socket="$2" - echo "$cmd" | awk -f "$SENDKEYS_AWK" | socat - UNIX-CONNECT:"$socket" -} - -main() { - # Get the QEMU socket and VM name dynamically - SOCKET=$(get_socket_path) - VM_NAME=$(basename "$SOCKET" -monitor.socket) - - # Debugging output to verify the socket and VM name - echo "[DEBUG] Using socket: $SOCKET" - echo "[DEBUG] VM name: $VM_NAME" - - # If no socket file is found, exit - if [[ ! -S "$SOCKET" ]]; then - echo "Error: QEMU monitor socket for $VM_NAME does not exist or is not available." - exit 1 - fi - - # Try to find the sendkeys.awk file - SENDKEYS_AWK=$(find_sendkeys_awk) - - echo "[*] Attempting Caps Lock to Super remapping on all known platforms..." - - # === X11 === - send_guest_command "setxkbmap -option caps:super" "$SOCKET" - send_guest_command "xmodmap -e 'remove Mod4 = Super_L Super_R'" "$SOCKET" - send_guest_command "xmodmap -e 'keycode 133 = NoSymbol'" "$SOCKET" - send_guest_command "xmodmap -e 'keycode 134 = NoSymbol'" "$SOCKET" - - # === Wayland (note: this just gives a reminder) === - send_guest_command "gsettings set org.gnome.desktop.input-sources xkb-options \"['caps:super']\"" "$SOCKET" - send_guest_command "echo 'Wayland? Try remapping via wlroots/wlr-keyboard'" "$SOCKET" - - # === Windows (registry scancode map) === - send_guest_command "powershell -Command \"Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout' -Name 'Scancode Map' -Value ([byte[]](0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x3A,0x00,0x5B,0x00,0x00,0x00))\"" "$SOCKET" - - # === macOS (hidutil remap) === - send_guest_command "hidutil property --set '{\"UserKeyMapping\":[{\"HIDKeyboardModifierMappingSrc\":0x700000039,\"HIDKeyboardModifierMappingDst\":0x7000000E3}]}'" "$SOCKET" - - echo "[*] Done sending remapping commands to guest." -} - -main "$@" diff --git a/unix/utils/heads-up-display b/unix/utils/heads-up-display deleted file mode 100755 index 54f5de1..0000000 --- a/unix/utils/heads-up-display +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/sh - -# Created By: srdusr -# Created On: Wed 05 Feb 2023 01:24:37 AM CAT -# Project: bspwm scratchpad (Heads-Up-Display) with tmux session - -### Alternative method - -#if id="$(xdo id -N heads-up-display)"; then -# bspc node "$id" -g hidden -f -#else -# #kitty --class "heads-up-display" -e tmux new-session -A -s HUD -e bash >/dev/null 2>&1 & -# wezterm start --class "heads-up-display" -e tmux new-session -A -s HUD -e bash >/dev/null 2>&1 & -#fi - -#- - - - - - - - - - - -### Alternative method - -#id=$(xdotool search --class heads-up-display) -#if [ "$id" = "" ]; then -# #kitty --class "Heads-Up-Display" -e tmux new-session -A -s HUD -e bash > /dev/null 2>&1 & -# alacritty --class "heads-up-display" -e tmux new-session -A -s HUD -e bash >/dev/null 2>&1 & -#else -# if [ ! -f /tmp/hide_hud ]; then -# touch /tmp/hide_hud && xdo hide "$id" -# elif [ -f /tmp/hide_hud ]; then -# rm /tmp/hide_hud && xdo show "$id" -# fi -#fi - - - -# Set the environment variables to x11 to allow working in Wayland -export GDK_BACKEND=x11 -export QT_QPA_PLATFORM=xcb -#export WAYLAND_DISPLAY="" -export WINIT_UNIX_BACKEND=x11 - -# Supported terminals and dropdown class -supported_terminals=("wezterm" "kitty" "alacritty") - -# Check if any supported terminal with scratchpad class is running -for term in "${supported_terminals[@]}"; do - if pgrep -f "$term.*--class heads-up-display" >/dev/null; then - my_term="$term" - break - fi -done - -# If no supported terminal is running, start the first available one -if [ "$my_term" = "" ]; then - for term in "${supported_terminals[@]}"; do - if command -v "$term" >/dev/null 2>&1; then - my_term="$term" - break - fi - done - if [ "$my_term" = "" ]; then - echo "No supported terminal found." && exit 1 - fi - - # Start terminal with scratchpad class - case "$my_term" in - "wezterm") wezterm start --class heads-up-display -e tmux new-session -A -s HUD -e bash htop & ;; - "kitty") kitty --class heads-up-display tmux new-session -A -s HUD -e bash htop & ;; - "alacritty") alacritty --class heads-up-display -e tmux new-session -A -s HUD -e bash htop & ;; - - esac -fi - -# Get the window ID of the scratchpad terminal -id="$(xdo id -N heads-up-display)" - -# Toggle scratchpad terminal visibility -if [ "$id" != "" ]; then - if xwininfo -id "$id" | grep "Map State: IsViewable" >/dev/null; then - # Scratchpad is visible, hide it - dimensions="$(xwininfo -id "$id" | awk '/Width:|Height:/ { printf("%s=%s;", tolower($1), $2) }')" - xdo hide "$id" 2>/dev/null - else - # Scratchpad is hidden, show it and restore dimensions - xdo show "$id" - xdotool windowsize "$id" "$(echo "$dimensions" | tr ';' ' ')" 2>/dev/null - xdotool windowactivate "$id" - xdotool windowfocus "$id" - fi -fi diff --git a/unix/utils/hex2rgb.sh b/unix/utils/hex2rgb.sh deleted file mode 100755 index a8ccc38..0000000 --- a/unix/utils/hex2rgb.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -hex="${1}" -printf "R: %d G: %d B: %d\n" 0x"${hex:0:2}" 0x"${hex:2:2}" 0x"${hex:4:2}" diff --git a/unix/utils/kill-notify b/unix/utils/kill-notify deleted file mode 100755 index f7f749e..0000000 --- a/unix/utils/kill-notify +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# Kills an application and sends a notification that it's been killed - -killall "$1" && notify-send "Killed $1" diff --git a/unix/utils/kill-process b/unix/utils/kill-process deleted file mode 100755 index 5247e5f..0000000 --- a/unix/utils/kill-process +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -# pipes list of processes into rofi/dmenu and kills the selection - -proc=$(ps -u $USER -o pid,%mem,%cpu,comm | sort -b -k2 -r | sed -n '1!p' | dmenu -i -p "Kill" | awk '{print $1,$4}') - -[ -z "$proc" ] || (kill -15 $(echo $proc | awk '{print $1}') 2>/dev/null && notify-send "$(echo $proc | awk '{print $2}') killed") diff --git a/unix/utils/mnt b/unix/utils/mnt deleted file mode 100755 index dc19ca9..0000000 --- a/unix/utils/mnt +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# mount disk -set -e -. ~/etc/colors/current - -d() case $LABEL in -Windows) echo "/win" ;; -*) echo "${1:-$HOME}/dev/$NAME" ;; -esac - -lsblk -Po NAME,SIZE,MOUNTPOINT,FSTYPE,LABEL | while read -r a; do - eval "$a" - - [ "$FSTYPE" ] && [ ! "$MOUNTPOINT" ] && - printf "%-4s:%s:%s:-> %s\n" \ - "$NAME" \ - "$SIZE" \ - "${LABEL:-unnamed}" \ - "$(d \~)" - -done | column -ts':' -o' ' | menu -p mount | { - read -r NAME _ - eval "$(lsblk -Polabel "/dev/$NAME")" - mkdir -p "$(d)" - sudo mount -o "umask=000" "/dev/$NAME" "$(d)" - notify-send summary "<span color='#$green'>$NAME: $LABEL</span>\n$(d \~)" -} diff --git a/unix/utils/move_terminal b/unix/utils/move_terminal deleted file mode 100755 index 2b447d0..0000000 --- a/unix/utils/move_terminal +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -SCRATCHPAD_CLASSES=("scratchpad" "pack" "heads-up-display") -PRIMARY_MONITOR="eDP-1" -SECOND_MONITOR="HDMI-A-2" - -PRIMARY_WORKSPACES=(2 4 5 6) -SECOND_WORKSPACES=(1 3) - -# Check if second monitor exists -if ! hyprctl monitors -j | jq -e ".[] | select(.name == \"$SECOND_MONITOR\")" >/dev/null; then - # No second monitor, do nothing - exit 0 -fi - -# Check if list of workspaces has any windows -has_windows_in_workspaces() { - local workspaces=("$@") - for ws in "${workspaces[@]}"; do - local count - count=$(hyprctl clients -j | jq "[.[] | select(.workspace.id == $ws)] | length") - if ((count > 0)); then - return 0 - fi - done - return 1 -} - -# Check window presence -primary_has_windows=false -second_has_windows=false - -if has_windows_in_workspaces "${PRIMARY_WORKSPACES[@]}"; then - primary_has_windows=true -fi -if has_windows_in_workspaces "${SECOND_WORKSPACES[@]}"; then - second_has_windows=true -fi - -# Decide target monitor -if [[ "$primary_has_windows" == true && "$second_has_windows" == false ]]; then - TARGET_MONITOR="$SECOND_MONITOR" -elif [[ "$primary_has_windows" == false && "$second_has_windows" == true ]]; then - TARGET_MONITOR="$PRIMARY_MONITOR" -else - TARGET_MONITOR="$SECOND_MONITOR" # both busy or both empty â second monitor -fi - -# Get workspace id of the target monitor -TARGET_WORKSPACE=$(hyprctl monitors -j | jq ".[] | select(.name == \"$TARGET_MONITOR\") | .activeWorkspace.id") - -# Wait for scratchpad window to appear and move it -for _ in {1..20}; do - for class in "${SCRATCHPAD_CLASSES[@]}"; do - client=$(hyprctl clients -j | jq -r ".[] | select(.class == \"$class\") | .address") - if [[ -n "$client" ]]; then - hyprctl dispatch movetoworkspacesilent "$TARGET_WORKSPACE,address:$client" - hyprctl dispatch focuswindow address:"$client" - exit 0 - fi - done - sleep 0.1 -done - -exit 1 diff --git a/unix/utils/neovim.sh b/unix/utils/neovim.sh deleted file mode 100755 index c9adcca..0000000 --- a/unix/utils/neovim.sh +++ /dev/null @@ -1,422 +0,0 @@ -#!/bin/bash - -# Created By: srdusr -# Created On: Sat 12 Aug 2023 13:11:39 CAT -# Project: Install/update/uninstall/change version Neovim script, primarily for Linux but may work in other platforms - -# Dependencies: wget/curl, fuse - -# Color definitions -RED='\033[0;31m' -GREEN='\033[0;32m' -NC='\033[0m' # No Color - -# Handle errors -handle_error() { - local message="$1" - printf "${RED}Error: $message${NC}\n" -} - -# Check if necessary dependencies are installed -check_dependencies() { - if [ -x "$(command -v wget)" ]; then - DOWNLOAD_COMMAND="wget" - elif [ -x "$(command -v curl)" ]; then - DOWNLOAD_COMMAND="curl" - else - printf "${RED}Error: Neither wget nor curl found. Please install one of them to continue!${NC}\n" - exit 1 - fi -} - -# Check for privilege escalation tools -check_privilege_tools() { - if [ -x "$(command -v sudo)" ]; then - PRIVILEGE_TOOL="sudo" - elif [ -x "$(command -v doas)" ]; then - PRIVILEGE_TOOL="doas" - elif [ -x "$(command -v pkexec)" ]; then - PRIVILEGE_TOOL="pkexec" - elif [ -x "$(command -v dzdo)" ]; then - PRIVILEGE_TOOL="dzdo" - elif [ "$(id -u)" -eq 0 ]; then - PRIVILEGE_TOOL="" # root - else - PRIVILEGE_TOOL="" # No privilege escalation mechanism found - printf "\n${RED}Error: No privilege escalation tool (sudo, doas, pkexec, dzdo, or root privileges) found. You may not have sufficient permissions to run this script.${NC}\n" - printf "\nAttempt to continue Installation (might fail without a privilege escalation tool)? [yes/no] " - read continue_choice - case $continue_choice in - [Yy] | [Yy][Ee][Ss]) ;; - [Nn] | [Nn][Oo]) exit ;; - *) handle_error "Invalid choice. Exiting..." && exit ;; - esac - fi -} - -# Check if Neovim is already installed -check_neovim_installed() { - if [ -x "$(command -v nvim)" ]; then - return 0 # Neovim is installed - else - return 1 # Neovim is not installed - fi -} - -# Nightly version -nightly_version() { - local url="https://github.com/neovim/neovim/releases/download/nightly/nvim-linux-x86_64.appimage" - install_neovim "$url" - local version_output=$(nvim --version) - version_id="Nightly $(echo "$version_output" | grep -oP 'NVIM \d+\.\d+\.\d+')" -} - -# Stable version -stable_version() { - #local url="https://github.com/neovim/neovim/releases/download/stable/nvim.appimage" - local url="https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.appimage" - install_neovim "$url" - local version_output=$(nvim --version) - version_id="Stable $(echo "$version_output" | grep -oP 'NVIM \d+\.\d+')" -} - -# Specific version -specific_version() { - local version="$1" - - # Add 'v' prefix if not present - if [[ $version != v* ]]; then - version="v$version" - fi - - local url="https://github.com/neovim/neovim/releases/download/$version/nvim-linux-x86_64.appimage" - install_neovim "$url" - local version_output=$(nvim --version) - version_id="Version $version $(echo "$version_output" | grep -oP 'NVIM \d+\.\d+\.\d+')" -} - -# Download a file using wget or curl -download_file() { - local url="$1" - local output="$2" - - if [ "$DOWNLOAD_COMMAND" = "wget" ]; then - if ! "$DOWNLOAD_COMMAND" -q --show-progress -O "$output" "$url"; then - handle_error "Download failed. Exiting..." - exit 1 - fi - elif [ "$DOWNLOAD_COMMAND" = "curl" ]; then - if ! "$DOWNLOAD_COMMAND" --progress-bar -# -o "$output" "$url"; then - handle_error "Download failed. Exiting..." - exit 1 - fi - else - echo "Unsupported download command: $DOWNLOAD_COMMAND" - exit 1 - fi -} - -# Check if a specific version of Neovim exists -version_exists() { - local version="$1" - - # Add 'v' prefix if not present - if [[ $version != v* ]]; then - version="v$version" - fi - - # Fetch all the release tags from GitHub - ALL_TAGS=$(curl -s "https://api.github.com/repos/neovim/neovim/tags" | grep '"name":' | cut -d '"' -f 4) - - # Check if the desired version is in the list of release tags - if echo "$ALL_TAGS" | grep -q "$version"; then - return 0 # Version exists - else - return 1 # Version does not exist - fi -} - -# Update Neovim to the latest version (nightly/stable) -update_version() { - valid_choice=false - while [ "$valid_choice" = false ]; do - # Determine which version to update to (nightly/stable) - printf "Select version to install/update to:\n" - printf " 1. Nightly\n" - printf " 2. Stable\n" - printf " 3. Choose specific version by tag\n" - printf "Enter the number corresponding to your choice (1/2/3): " - read update_choice - - case $update_choice in - 1) - version="Nightly" - nightly_version - valid_choice=true - ;; - 2) - version="Stable" - stable_version - valid_choice=true - ;; - 3) - # Ask user for specific version - read -p "Enter the specific version (e.g., v0.1.0): " version - # Normalize version - if [[ $version != v* ]]; then - version="v$version" - fi - # Check if the specific version exists on GitHub releases - if version_exists "$version"; then - # Install specific version - specific_version "$version" # Pass the normalized version to the function - valid_choice=true - else - printf "${RED}The specified version $version does not exist.${NC}\n" - fi - ;; - - *) - handle_error "Invalid choice. Please enter a valid option (1, 2 or 3)." - ;; - esac - done - -} - -# Install Neovim -install_neovim() { - local url="$1" - local install_action="$3" - - if [ "$install_action" = "installed" ]; then - printf "Downloading and installing Neovim $version...\n" - else - printf "${GREEN}Updating Neovim to the latest version ($version)...${NC}\n" - fi - - # Determine the platform-specific installation steps - case "$(uname -s)" in - Linux) - printf "Detected Linux OS.\n" - if [ -x "$(command -v fusermount)" ]; then - printf "FUSE is available. Downloading and running the AppImage...\n" - download_file "$url" "nvim.appimage" - chmod u+x nvim.appimage - "$PRIVILEGE_TOOL" cp nvim.appimage /usr/local/bin/nvim - "$PRIVILEGE_TOOL" mv nvim.appimage /usr/bin/nvim - else - printf "FUSE is not available. Downloading and extracting the AppImage...\n" - download_file "$url" "nvim.appimage" - chmod u+x nvim.appimage - ./nvim.appimage --appimage-extract - "$PRIVILEGE_TOOL" cp squashfs-root/usr/bin/nvim /usr/local/bin - "$PRIVILEGE_TOOL" mv squashfs-root/usr/bin/nvim /usr/bin - fi - ;; - - Darwin) - printf "Detected macOS.\n" - download_file "$url" "nvim-macos.tar.gz" - xattr -c ./nvim-macos.tar.gz - tar xzvf nvim-macos.tar.gz - "$PRIVILEGE_TOOL" cp nvim-macos/bin/nvim /usr/local/bin - "$PRIVILEGE_TOOL" mv nvim-macos/bin/nvim /usr/bin/nvim - ;; - - MINGW*) - printf "Detected Windows.\n" - download_file "$url" "nvim.appimage" - chmod +x nvim.appimage - if [ "$PRIVILEGE_TOOL" = "sudo" ]; then - "$PRIVILEGE_TOOL" cp nvim.appimage /usr/local/bin/nvim - "$PRIVILEGE_TOOL" mv /usr/local/bin/nvim /usr/bin - elif [ "$PRIVILEGE_TOOL" = "" ]; then - cp nvim.appimage /usr/local/bin/nvim - mv /usr/local/bin/nvim /usr/bin - else - printf "No privilege escalation tool found. Cannot install Neovim on Windows.\n" - fi - ;; - - *) - printf "Unsupported operating system.\n" - exit 1 - ;; - esac - # Check if the installation was successful - if [ $? -eq 0 ]; then - if [ "$install_action" = "installed" ]; then - printf "${GREEN}Neovim $version has been installed successfully!${NC}\n" - else - printf "${GREEN}Neovim has been updated successfully to $version!${NC}\n" - fi - else - printf "${RED}Error: Neovim installation/update failed.${NC}\n" - exit 1 - fi -} - -# Uninstall Neovim -uninstall_neovim() { - printf "${RED}Uninstalling Neovim...${NC}\n" - - # Detect the operating system to determine the appropriate uninstallation method - case "$(uname -s)" in - Linux) - printf "Detected Linux OS.\n" - "$PRIVILEGE_TOOL" rm /usr/local/bin/nvim - "$PRIVILEGE_TOOL" rm /usr/bin/nvim - ;; - - Darwin) - printf "Detected macOS.\n" - "$PRIVILEGE_TOOL" rm /usr/local/bin/nvim - "$PRIVILEGE_TOOL" rm /usr/bin/nvim - ;; - - MINGW*) - printf "Detected Windows.\n" - if [ "$PRIVILEGE_TOOL" = "sudo" ]; then - "$PRIVILEGE_TOOL" rm /usr/local/bin/nvim - "$PRIVILEGE_TOOL" rm /usr/bin/nvim - else - [ "$PRIVILEGE_TOOL" = "" ] - rm /usr/local/bin/nvim - rm /usr/bin/nvim - fi - ;; - *) - printf "Unsupported operating system.\n" - ;; - esac - - printf "${GREEN}Neovim has been uninstalled successfully!${NC}\n" -} - -# Check if Neovim is running -check_neovim_running() { - if pgrep nvim >/dev/null; then - printf "${RED}Error: Neovim is currently running. Please close Neovim before proceeding.${NC}\n" - read -p "Do you want to forcefully terminate Neovim and continue? [yes/no] " terminate_choice - - case $terminate_choice in - [Yy] | [Yy][Ee][Ss]) - pkill nvim # Forcefully terminate Neovim - ;; - [Nn] | [Nn][Oo]) - echo "Exiting..." - exit 1 - ;; - *) - handle_error "Invalid choice." - ;; - esac - fi -} - -check_neovim_running - -# Define the variable to control the prompt -SHOW_PROMPT=1 - -# Check if necessary dependencies are installed -check_dependencies - -# Check for privilege escalation tools -check_privilege_tools - -# Check if Neovim is already installed and ask the user if want to install it -if check_neovim_installed; then - printf "${GREEN}Neovim is already installed!${NC}\n" -else - printf "${RED}Neovim is not installed.${NC}\n" - read -p "Install Neovim? (y/n): " install_choice - - case $install_choice in - [Yy]) - update_version - ;; - [Nn]) - echo "Exiting..." - exit - ;; - *) - handle_error "Invalid choice. Please enter 'y' for yes or 'n' for no." - ;; - esac -fi - -# Check for updates and display breaking changes -check_version_updates() { - local latest_version_url="https://api.github.com/repos/neovim/neovim/releases/latest" - local latest_version="" - - if [ -x "$(command -v curl)" ]; then - latest_version=$(curl -sSL "$latest_version_url" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') - elif [ -x "$(command -v wget)" ]; then - latest_version=$(wget -qO - "$latest_version_url" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') - else - printf "${RED}Error: Neither curl nor wget found. Please install one of them to continue!${NC}\n" - exit 1 - fi - - if version_exists "$latest_version"; then - printf "${GREEN}An update is available!${NC}\n" - display_breaking_changes "$latest_version" - else - printf "You have the latest version of Neovim.\n" - fi -} - -# To display breaking changes for a specific version -display_breaking_changes() { - local version="$1" - local changelog_url="https://github.com/neovim/neovim/releases/tag/$version" - local changelog="" - - if [ -x "$(command -v curl)" ]; then - changelog=$(curl -sSL "$changelog_url" | grep -oE '<h1>Breaking Changes.*?</ul>' | sed 's/<[^>]*>//g') - elif [ -x "$(command -v wget)" ]; then - changelog=$(wget -qO - "$changelog_url" | grep -oE '<h1>Breaking Changes.*?</ul>' | sed 's/<[^>]*>//g') - else - printf "${RED}Error: Neither curl nor wget found. Please install one of them to continue!${NC}\n" - exit 1 - fi - - printf "\nBreaking Changes in Neovim $version:\n" - printf "$changelog\n" -} - -# Main loop -while [ "$SHOW_PROMPT" -gt 0 ]; do - printf "Select an option:\n" - printf " 1. Install/update Neovim\n" - printf " 2. Check for updates\n" - printf " 3. Uninstall Neovim\n" - printf " 4. Run Neovim\n" - printf " 5. Quit\n" - read -p "Enter a number or press 'q' to quit: " choice - - case $choice in - 1) - update_version - ;; - 2) - check_version_updates - ;; - 3) - uninstall_neovim - ;; - 4) - nvim - ;; - 5 | [Qq]) - echo "Exiting..." - exit - ;; - *) - handle_error "Invalid choice. Please choose a valid option by entering the corresponding number or press 'q' to 'quit'." - ;; - esac -done diff --git a/unix/utils/pack b/unix/utils/pack deleted file mode 100755 index 4b8760c..0000000 --- a/unix/utils/pack +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/sh - -# Created By: srdusr -# Created On: Wed 05 Feb 2023 01:24:37 AM CAT -# Project: bspwm scratchpad (pack) with tmux session - -### Alternative method - -#if id="$(xdo id -N pack)"; then -# bspc node "$id" -g hidden -f -#else -# #kitty --class "pack" -e tmux new-session -A -s pack -e bash >/dev/null 2>&1 & -# wezterm start --class "pack" -e tmux new-session -A -s pack -e bash >/dev/null 2>&1 & -#fi - -#- - - - - - - - - - - -### Alternative method - -#id=$(xdotool search --class pack) -#if [ "$id" = "" ]; then -# #kitty --class "pack" -e tmux new-session -A -s pack -e bash > /dev/null 2>&1 & -# alacritty --class "pack" -e tmux new-session -A -s pack -e bash >/dev/null 2>&1 & -#else -# if [ ! -f /tmp/hide_hud ]; then -# touch /tmp/hide_hud && xdo hide "$id" -# elif [ -f /tmp/hide_hud ]; then -# rm /tmp/hide_hud && xdo show "$id" -# fi -#fi - - - -# Set the environment variables to x11 to allow working in Wayland -export GDK_BACKEND=x11 -export QT_QPA_PLATFORM=xcb -#export WAYLAND_DISPLAY="" -export WINIT_UNIX_BACKEND=x11 - -# Supported terminals and dropdown class -supported_terminals=("wezterm" "kitty" "alacritty") - -# Check if any supported terminal with scratchpad class is running -for term in "${supported_terminals[@]}"; do - if pgrep -f "$term.*--class pack" >/dev/null; then - my_term="$term" - break - fi -done - -# If no supported terminal is running, start the first available one -if [ "$my_term" = "" ]; then - for term in "${supported_terminals[@]}"; do - if command -v "$term" >/dev/null 2>&1; then - my_term="$term" - break - fi - done - if [ "$my_term" = "" ]; then - echo "No supported terminal found." && exit 1 - fi - - # Start terminal with scratchpad class - case "$my_term" in - "wezterm") wezterm start --class pack -e tmux new-session -A -s pack -e bash & ;; - "kitty") kitty --class pack tmux new-session -A -s pack -e bash & ;; - "alacritty") alacritty --class pack -e tmux new-session -A -s pack -e bash & ;; - - esac -fi - -# Get the window ID of the scratchpad terminal -id="$(xdo id -N pack)" - -# Toggle scratchpad terminal visibility -if [ "$id" != "" ]; then - if xwininfo -id "$id" | grep "Map State: IsViewable" >/dev/null; then - # Scratchpad is visible, hide it - dimensions="$(xwininfo -id "$id" | awk '/Width:|Height:/ { printf("%s=%s;", tolower($1), $2) }')" - xdo hide "$id" 2>/dev/null - else - # Scratchpad is hidden, show it and restore dimensions - xdo show "$id" - xdotool windowsize "$id" "$(echo "$dimensions" | tr ';' ' ')" 2>/dev/null - xdotool windowactivate "$id" - xdotool windowfocus "$id" - fi -fi diff --git a/unix/utils/rofi-network-manager.sh b/unix/utils/rofi-network-manager.sh deleted file mode 100755 index 61106d2..0000000 --- a/unix/utils/rofi-network-manager.sh +++ /dev/null @@ -1,252 +0,0 @@ -#!/bin/bash - -# Credit: https://github.com/P3rf/rofi-network-manager - -# Default Values -LOCATION=0 -QRCODE_LOCATION=$LOCATION -Y_AXIS=0 -X_AXIS=0 -NOTIFICATIONS="off" -QRCODE_DIR="/tmp/" -WIDTH_FIX_MAIN=1 -WIDTH_FIX_STATUS=10 -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PASSWORD_ENTER="if connection is stored,hit enter/esc." -WIRELESS_INTERFACES=("$(nmcli device | awk '$2=="wifi" {print $1}')") -WIRELESS_INTERFACES_PRODUCT=() -WLAN_INT=0 -WIRED_INTERFACES=("$(nmcli device | awk '$2=="ethernet" {print $1}')") -WIRED_INTERFACES_PRODUCT=() -ASCII_OUT=false -CHANGE_BARS=false -SIGNAL_STRENGTH_0="0" -SIGNAL_STRENGTH_1="1" -SIGNAL_STRENGTH_2="12" -SIGNAL_STRENGTH_3="123" -SIGNAL_STRENGTH_4="1234" -VPN_PATTERN='(wireguard|vpn)' -function initialization() { - # Try to source configuration files from .config/rofi/ - if [[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/rofi/rofi-network-manager.conf" ]]; then - source "${XDG_CONFIG_HOME:-$HOME/.config}/rofi/rofi-network-manager.conf" - RASI_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/rofi/rofi-network-manager.rasi" - elif [[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/rofi/rofi-network-manager.rasi" ]]; then - source "${XDG_CONFIG_HOME:-$HOME/.config}/rofi/rofi-network-manager.rasi" - else - # Fallback to using files in the script's directory - source "$DIR/rofi-network-manager.conf" || source "$DIR/rofi-network-manager.conf" - [[ -f "$DIR/rofi-network-manager.rasi" ]] && RASI_DIR="$DIR/rofi-network-manager.rasi" - fi - for i in "${WIRELESS_INTERFACES[@]}"; do WIRELESS_INTERFACES_PRODUCT+=("$(nmcli -f general.product device show "$i" | awk '{print $2}')"); done - for i in "${WIRED_INTERFACES[@]}"; do WIRED_INTERFACES_PRODUCT+=("$(nmcli -f general.product device show "$i" | awk '{print $2}')"); done - wireless_interface_state && ethernet_interface_state -} -function notification() { - [[ "$NOTIFICATIONS" == "true" && -x "$(command -v notify-send)" ]] && notify-send -r "5" -u "normal" "$1" "$2" -} -function wireless_interface_state() { - - [[ ${#WIRELESS_INTERFACES[@]} -eq "0" ]] || { - ACTIVE_SSID=$(nmcli device status | grep "^${WIRELESS_INTERFACES[WLAN_INT]}." | awk '{print $4}') - WIFI_CON_STATE=$(nmcli device status | grep "^${WIRELESS_INTERFACES[WLAN_INT]}." | awk '{print $3}') - { [[ "$WIFI_CON_STATE" == "unavailable" ]] && WIFI_LIST="***Wi-Fi Disabled***" && WIFI_SWITCH="~Wi-Fi On" && OPTIONS="${WIFI_LIST}\n${WIFI_SWITCH}\n~Scan\n"; } || { [[ "$WIFI_CON_STATE" =~ "connected" ]] && { - PROMPT=${WIRELESS_INTERFACES_PRODUCT[WLAN_INT]}[${WIRELESS_INTERFACES[WLAN_INT]}] - WIFI_LIST=$(nmcli --fields SSID,SECURITY,BARS device wifi list ifname "${WIRELESS_INTERFACES[WLAN_INT]}") - wifi_list - [[ "$ACTIVE_SSID" == "--" ]] && WIFI_SWITCH="~Scan\n~Manual/Hidden\n~Wi-Fi Off" || WIFI_SWITCH="~Scan\n~Disconnect\n~Manual/Hidden\n~Wi-Fi Off" - OPTIONS="${WIFI_LIST}\n${WIFI_SWITCH}\n" - }; } - } -} -function ethernet_interface_state() { - [[ ${#WIRED_INTERFACES[@]} -eq "0" ]] || { - WIRED_CON_STATE=$(nmcli device status | grep "ethernet" | head -1 | awk '{print $3}') - { [[ "$WIRED_CON_STATE" == "disconnected" ]] && WIRED_SWITCH="~Eth On"; } || { [[ "$WIRED_CON_STATE" == "connected" ]] && WIRED_SWITCH="~Eth Off"; } || { [[ "$WIRED_CON_STATE" == "unavailable" ]] && WIRED_SWITCH="***Wired Unavailable***"; } || { [[ "$WIRED_CON_STATE" == "connecting" ]] && WIRED_SWITCH="***Wired Initializing***"; } - OPTIONS="${OPTIONS}${WIRED_SWITCH}\n" - } -} -function rofi_menu() { - { [[ ${#WIRELESS_INTERFACES[@]} -gt "1" ]] && OPTIONS="${OPTIONS}~Change Wifi Interface\n~More Options"; } || { OPTIONS="${OPTIONS}~More Options"; } - { [[ "$WIRED_CON_STATE" == "connected" ]] && PROMPT="${WIRED_INTERFACES_PRODUCT}[$WIRED_INTERFACES]"; } || PROMPT="${WIRELESS_INTERFACES_PRODUCT[WLAN_INT]}[${WIRELESS_INTERFACES[WLAN_INT]}]" - SELECTION=$(echo -e "$OPTIONS" | rofi_cmd "$OPTIONS" "$WIDTH_FIX_MAIN" "-a 0") - SSID=$(echo "$SELECTION" | sed "s/\s\{2,\}/\|/g" | awk -F "|" '{print $1}') - selection_action -} -function rofi_cmd() { - { [[ -n "${1}" ]] && WIDTH=$(echo -e "$1" | awk '{print length}' | sort -n | tail -1) && ((WIDTH += $2)) && ((WIDTH = WIDTH / 2)); } || { ((WIDTH = $2 / 2)); } - rofi -dmenu -i -location "$LOCATION" -yoffset "$Y_AXIS" -xoffset "$X_AXIS" "$3" -theme "$RASI_DIR" -theme-str 'window{width: '"$WIDTH"'em;}textbox-prompt-colon{str:"'"$PROMPT"':";}'"$4"'' -} -function change_wireless_interface() { - { [[ ${#WIRELESS_INTERFACES[@]} -eq "2" ]] && { [[ $WLAN_INT -eq "0" ]] && WLAN_INT=1 || WLAN_INT=0; }; } || { - LIST_WLAN_INT="" - for i in "${!WIRELESS_INTERFACES[@]}"; do LIST_WLAN_INT=("${LIST_WLAN_INT[@]}${WIRELESS_INTERFACES_PRODUCT[$i]}[${WIRELESS_INTERFACES[$i]}]\n"); done - LIST_WLAN_INT[-1]=${LIST_WLAN_INT[-1]::-2} - CHANGE_WLAN_INT=$(echo -e "${LIST_WLAN_INT[@]}" | rofi_cmd "${LIST_WLAN_INT[@]}" "$WIDTH_FIX_STATUS") - for i in "${!WIRELESS_INTERFACES[@]}"; do [[ $CHANGE_WLAN_INT == "${WIRELESS_INTERFACES_PRODUCT[$i]}[${WIRELESS_INTERFACES[$i]}]" ]] && WLAN_INT=$i && break; done - } - wireless_interface_state && ethernet_interface_state - rofi_menu -} -function scan() { - [[ "$WIFI_CON_STATE" =~ "unavailable" ]] && change_wifi_state "Wi-Fi" "Enabling Wi-Fi connection" "on" && sleep 2 - notification "-t 0 Wifi" "Please Wait Scanning" - WIFI_LIST=$(nmcli --fields SSID,SECURITY,BARS device wifi list ifname "${WIRELESS_INTERFACES[WLAN_INT]}" --rescan yes) - wifi_list - wireless_interface_state && ethernet_interface_state - notification "-t 1 Wifi" "Please Wait Scanning" - rofi_menu -} -function wifi_list() { - WIFI_LIST=$(echo -e "$WIFI_LIST" | awk -F' +' '{ if (!seen[$1]++) print}' | awk '$1!="--" {print}' | awk '$1 !~ "^'"$ACTIVE_SSID"'"') - [[ $ASCII_OUT == "true" ]] && WIFI_LIST=$(echo -e "$WIFI_LIST" | sed 's/\(..*\)\*\{4,4\}/\1ââââ/g' | sed 's/\(..*\)\*\{3,3\}/\1âââ_/g' | sed 's/\(..*\)\*\{2,2\}/\1ââ__/g' | sed 's/\(..*\)\*\{1,1\}/\1â___/g') - [[ $CHANGE_BARS == "true" ]] && WIFI_LIST=$(echo -e "$WIFI_LIST" | sed 's/\(.*\)ââââ/\1'"$SIGNAL_STRENGTH_4"'/' | sed 's/\(.*\)âââ_/\1'"$SIGNAL_STRENGTH_3"'/' | sed 's/\(.*\)ââ__/\1'"$SIGNAL_STRENGTH_2"'/' | sed 's/\(.*\)â___/\1'"$SIGNAL_STRENGTH_1"'/' | sed 's/\(.*\)____/\1'"$SIGNAL_STRENGTH_0"'/') -} -function change_wifi_state() { - notification "$1" "$2" - nmcli radio wifi "$3" -} -function change_wired_state() { - notification "$1" "$2" - nmcli device "$3" "$4" -} -function net_restart() { - notification "$1" "$2" - nmcli networking off && sleep 3 && nmcli networking on -} -function disconnect() { - ACTIVE_SSID=$(nmcli -t -f GENERAL.CONNECTION dev show "${WIRELESS_INTERFACES[WLAN_INT]}" | cut -d ':' -f2) - notification "$1" "You're now disconnected from Wi-Fi network '$ACTIVE_SSID'" - nmcli con down id "$ACTIVE_SSID" -} -function check_wifi_connected() { - [[ "$(nmcli device status | grep "^${WIRELESS_INTERFACES[WLAN_INT]}." | awk '{print $3}')" == "connected" ]] && disconnect "Connection_Terminated" -} -function connect() { - check_wifi_connected - notification "-t 0 Wi-Fi" "Connecting to $1" - { [[ $(nmcli dev wifi con "$1" password "$2" ifname "${WIRELESS_INTERFACES[WLAN_INT]}" | grep -c "successfully activated") -eq "1" ]] && notification "Connection_Established" "You're now connected to Wi-Fi network '$1'"; } || notification "Connection_Error" "Connection can not be established" -} -function enter_passwword() { - PROMPT="Enter_Password" && PASS=$(echo "$PASSWORD_ENTER" | rofi_cmd "$PASSWORD_ENTER" 4 "-password") -} -function enter_ssid() { - PROMPT="Enter_SSID" && SSID=$(rofi_cmd "" 40) -} -function stored_connection() { - check_wifi_connected - notification "-t 0 Wi-Fi" "Connecting to $1" - { [[ $(nmcli dev wifi con "$1" ifname "${WIRELESS_INTERFACES[WLAN_INT]}" | grep -c "successfully activated") -eq "1" ]] && notification "Connection_Established" "You're now connected to Wi-Fi network '$1'"; } || notification "Connection_Error" "Connection can not be established" -} -function ssid_manual() { - enter_ssid - [[ -n $SSID ]] && { - enter_passwword - { [[ -n "$PASS" ]] && [[ "$PASS" != "$PASSWORD_ENTER" ]] && connect "$SSID" "$PASS"; } || stored_connection "$SSID" - } -} -function ssid_hidden() { - enter_ssid - [[ -n $SSID ]] && { - enter_passwword && check_wifi_connected - [[ -n "$PASS" ]] && [[ "$PASS" != "$PASSWORD_ENTER" ]] && { - nmcli con add type wifi con-name "$SSID" ssid "$SSID" ifname "${WIRELESS_INTERFACES[WLAN_INT]}" - nmcli con modify "$SSID" wifi-sec.key-mgmt wpa-psk - nmcli con modify "$SSID" wifi-sec.psk "$PASS" - } || [[ $(nmcli -g NAME con show | grep -c "$SSID") -eq "0" ]] && nmcli con add type wifi con-name "$SSID" ssid "$SSID" ifname "${WIRELESS_INTERFACES[WLAN_INT]}" - notification "-t 0 Wifi" "Connecting to $SSID" - { [[ $(nmcli con up id "$SSID" | grep -c "successfully activated") -eq "1" ]] && notification "Connection_Established" "You're now connected to Wi-Fi network '$SSID'"; } || notification "Connection_Error" "Connection can not be established" - } -} -function interface_status() { - local -n INTERFACES="$1" && local -n INTERFACES_PRODUCT="$2" - for i in "${!INTERFACES[@]}"; do - CON_STATE=$(nmcli device status | grep "^${INTERFACES[$i]}." | awk '{print $3}') - INT_NAME=${INTERFACES_PRODUCT[$i]}[${INTERFACES[$i]}] - [[ "$CON_STATE" == "connected" ]] && STATUS="$INT_NAME:\n\t$(nmcli -t -f GENERAL.CONNECTION dev show "${INTERFACES[$i]}" | awk -F '[:]' '{print $2}') ~ $(nmcli -t -f IP4.ADDRESS dev show "${INTERFACES[$i]}" | awk -F '[:/]' '{print $2}')" || STATUS="$INT_NAME: ${CON_STATE^}" - echo -e "$STATUS" - done -} -function status() { - OPTIONS="" - [[ ${#WIRED_INTERFACES[@]} -ne "0" ]] && ETH_STATUS="$(interface_status WIRED_INTERFACES WIRED_INTERFACES_PRODUCT)" && OPTIONS="${OPTIONS}${ETH_STATUS}" - [[ ${#WIRELESS_INTERFACES[@]} -ne "0" ]] && WLAN_STATUS="$(interface_status WIRELESS_INTERFACES WIRELESS_INTERFACES_PRODUCT)" && { [[ -n ${OPTIONS} ]] && OPTIONS="${OPTIONS}\n${WLAN_STATUS}" || OPTIONS="${OPTIONS}${WLAN_STATUS}"; } - ACTIVE_VPN=$(nmcli -g NAME,TYPE con show --active | awk '/:'"$VPN_PATTERN"'/ {sub(/:'"$VPN_PATTERN"'.*/, ""); print}') - [[ -n $ACTIVE_VPN ]] && OPTIONS="${OPTIONS}\n${ACTIVE_VPN}[VPN]: $(nmcli -g ip4.address con show "$ACTIVE_VPN" | awk -F '[:/]' '{print $1}')" - echo -e "$OPTIONS" | rofi_cmd "$OPTIONS" "$WIDTH_FIX_STATUS" "" "mainbox{children:[listview];}" -} -function share_pass() { - SSID=$(nmcli dev wifi show-password | grep -oP '(?<=SSID: ).*' | head -1) - PASSWORD=$(nmcli dev wifi show-password | grep -oP '(?<=Password: ).*' | head -1) - OPTIONS="SSID: ${SSID}\nPassword: ${PASSWORD}" - [[ -x "$(command -v qrencode)" ]] && OPTIONS="${OPTIONS}\n~QrCode" - SELECTION=$(echo -e "$OPTIONS" | rofi_cmd "$OPTIONS" "$WIDTH_FIX_STATUS" "-a -1" "mainbox{children:[listview];}") - selection_action -} -function gen_qrcode() { - DIRECTIONS=("Center" "Northwest" "North" "Northeast" "East" "Southeast" "South" "Southwest" "West") - TMP_SSID="${SSID// /_}" - [[ -e $QRCODE_DIR$TMP_SSID.png ]] || qrencode -t png -o "$QRCODE_DIR$TMP_SSID".png -l H -s 25 -m 2 --dpi=192 "WIFI:S:""$SSID"";T:""$(nmcli dev wifi show-password | grep -oP '(?<=Security: ).*' | head -1)"";P:""$PASSWORD"";;" - rofi_cmd "" "0" "" "entry{enabled:false;}window{location:""${DIRECTIONS[QRCODE_LOCATION]}"";border-radius:6mm;padding:1mm;width:100mm;height:100mm; - background-image:url(\"$QRCODE_DIR$TMP_SSID.png\",both);}" -} -function manual_hidden() { - OPTIONS="~Manual\n~Hidden" && SELECTION=$(echo -e "$OPTIONS" | rofi_cmd "$OPTIONS" "$WIDTH_FIX_STATUS" "" "mainbox{children:[listview];}") - selection_action -} -function vpn() { - ACTIVE_VPN=$(nmcli -g NAME,TYPE con show --active | awk '/:'"$VPN_PATTERN"'/ {sub(/:'"$VPN_PATTERN"'.*/, ""); print}') - [[ $ACTIVE_VPN ]] && OPTIONS="~Deactive $ACTIVE_VPN" || OPTIONS="$(nmcli -g NAME,TYPE connection | awk '/:'"$VPN_PATTERN"'/ {sub(/:'"$VPN_PATTERN"'.*/, ""); print}')" - VPN_ACTION=$(echo -e "$OPTIONS" | rofi_cmd "$OPTIONS" "$WIDTH_FIX_STATUS" "" "mainbox {children:[listview];}") - [[ -n "$VPN_ACTION" ]] && { { [[ "$VPN_ACTION" =~ "~Deactive" ]] && nmcli connection down "$ACTIVE_VPN" && notification "VPN_Deactivated" "$ACTIVE_VPN"; } || { - notification "-t 0 Activating_VPN" "$VPN_ACTION" - VPN_OUTPUT=$(nmcli connection up "$VPN_ACTION" 2>/dev/null) - { [[ $(echo "$VPN_OUTPUT" | grep -c "Connection successfully activated") -eq "1" ]] && notification "VPN_Successfully_Activated" "$VPN_ACTION"; } || notification "Error_Activating_VPN" "Check your configuration for $VPN_ACTION" - }; } -} -function more_options() { - OPTIONS="" - [[ "$WIFI_CON_STATE" == "connected" ]] && OPTIONS="~Share Wifi Password\n" - OPTIONS="${OPTIONS}~Status\n~Restart Network" - [[ $(nmcli -g NAME,TYPE connection | awk '/:'"$VPN_PATTERN"'/ {sub(/:'"$VPN_PATTERN"'.*/, ""); print}') ]] && OPTIONS="${OPTIONS}\n~VPN" - [[ -x "$(command -v nm-connection-editor)" ]] && OPTIONS="${OPTIONS}\n~Open Connection Editor" - SELECTION=$(echo -e "$OPTIONS" | rofi_cmd "$OPTIONS" "$WIDTH_FIX_STATUS" "" "mainbox {children:[listview];}") - selection_action -} -function selection_action() { - case "$SELECTION" in - "~Disconnect") disconnect "Connection_Terminated" ;; - "~Scan") scan ;; - "~Status") status ;; - "~Share Wifi Password") share_pass ;; - "~Manual/Hidden") manual_hidden ;; - "~Manual") ssid_manual ;; - "~Hidden") ssid_hidden ;; - "~Wi-Fi On") change_wifi_state "Wi-Fi" "Enabling Wi-Fi connection" "on" ;; - "~Wi-Fi Off") change_wifi_state "Wi-Fi" "Disabling Wi-Fi connection" "off" ;; - "~Eth Off") change_wired_state "Ethernet" "Disabling Wired connection" "disconnect" "$WIRED_INTERFACES" ;; - "~Eth On") change_wired_state "Ethernet" "Enabling Wired connection" "connect" "$WIRED_INTERFACES" ;; - "***Wi-Fi Disabled***") ;; - "***Wired Unavailable***") ;; - "***Wired Initializing***") ;; - "~Change Wifi Interface") change_wireless_interface ;; - "~Restart Network") net_restart "Network" "Restarting Network" ;; - "~QrCode") gen_qrcode ;; - "~More Options") more_options ;; - "~Open Connection Editor") nm-connection-editor ;; - "~VPN") vpn ;; - *) - [[ -n "$SELECTION" ]] && [[ "$WIFI_LIST" =~ .*"$SELECTION".* ]] && { - [[ "$SSID" == "*" ]] && SSID=$(echo "$SELECTION" | sed "s/\s\{2,\}/\|/g " | awk -F "|" '{print $3}') - { [[ "$ACTIVE_SSID" == "$SSID" ]] && nmcli con up "$SSID" ifname "${WIRELESS_INTERFACES[WLAN_INT]}"; } || { - [[ "$SELECTION" =~ "WPA2" ]] || [[ "$SELECTION" =~ "WEP" ]] && enter_passwword - { [[ -n "$PASS" ]] && [[ "$PASS" != "$PASSWORD_ENTER" ]] && connect "$SSID" "$PASS"; } || stored_connection "$SSID" - } - } - ;; - esac -} -function main() { - initialization && rofi_menu -} -main diff --git a/unix/utils/root.sh b/unix/utils/root.sh deleted file mode 100755 index a7807bc..0000000 --- a/unix/utils/root.sh +++ /dev/null @@ -1,152 +0,0 @@ -#!/bin/bash - -# Created By: srdusr -# Created On: Mon 19 Feb 2025 14:18:00 PM CAT -# Project: Backup and restore system files to/from home extras (system dotfiles) directory - -# Dependencies: None -# NOTE: The backups will be stored in the ~/extras directory, preserving the original file structure. Run as sudo or be prompted for password -# Example usage: -# To backup a specific file: root.sh --backup /some_directory/some_file.conf -# To restore a specific file: root.sh --restore ~/extras/some_directory/some_file.conf -# To restore all files: root.sh --restore -# - -# Use $SUDO_USER to get the original user when run with sudo, or fall back to the current user if not -BASE_DIR="/home/${SUDO_USER:-$(whoami)}/extras" - -if [ "$EUID" -eq 0 ] && [ "$SUDO_USER" = "" ]; then - echo "You are running this script directly as root, not through sudo!" - exit 1 -fi - -if [ "$EUID" -ne 0 ]; then - echo "Elevating to sudo..." - exec sudo "$0" "$@" # Re-run the script with sudo -fi - -# Create directories if they do not exist -create_directory() { - local dir=$1 - if [ ! -d "$dir" ]; then - echo "Creating directory: $dir" - mkdir -p "$dir" - else - echo "Directory already exists: $dir" - fi -} - -# Backup files -backup_to_extras() { - local src=$1 - - # Ensure the file or directory exists - if [ -e "$src" ]; then - # Strip the leading / from src to avoid double slashes - local stripped_src="${src#/}" - - # Determine the destination path - dest_dir="$BASE_DIR/$(dirname "$stripped_src")" # Get the directory part of the source - dest_file="$BASE_DIR/$stripped_src" # Get the full destination file path - - # Debug: Print paths - echo "Source file: $src" - echo "Destination directory: $dest_dir" - echo "Destination file: $dest_file" - - # Create the necessary directories in extras if they don't exist - create_directory "$dest_dir" - - # Backup the file to extras - echo "Backing up $src to $dest_file" - cp -p "$src" "$dest_file" - - # Set permission to user - chown "$SUDO_USER:$SUDO_USER" "$dest_file" - - echo "Backup of $src completed." - else - echo "Error: The file or directory '$src' does not exist." - fi -} - -# Restore files -restore_from_extras() { - local src=$1 - - # Ensure the file or directory exists in extras - if [ -e "$src" ]; then - # Strip the leading / from src to avoid double slashes - local stripped_src="${src#/}" - - # Determine the destination path - dest_dir="/$(dirname "$stripped_src")" # Get the directory part of the source - dest_file="/$stripped_src" # Get the full destination file path - - # Debug: Print paths - echo "Source file: $src" - echo "Destination directory: $dest_dir" - echo "Destination file: $dest_file" - - # Create the necessary directories in the system if they don't exist - create_directory "$dest_dir" - - # Backup the file if it exists before restoring - if [ -e "$dest_file" ]; then - echo "File $dest_file exists, creating a backup..." - mv "$dest_file" "$dest_file.bak" - echo "Backup created at $dest_file.bak" - fi - - # Restore the file from extras - echo "Restoring $src to $dest_file" - cp -p "$BASE_DIR/$stripped_src" "$dest_file" - - # Set permissions for the restored file - chmod 644 "$dest_file" - - echo "Restore of $src completed." - else - echo "Error: The file or directory '$src' does not exist in extras." - fi -} - -# Restore all files from extras -restore_all_from_extras() { - echo "Restoring all files and directories from extras..." - - # Loop over all files and directories in BASE_DIR and restore them - find "$BASE_DIR" -type f | while read -r file; do - restore_from_extras "$file" - done - - echo "Restore completed." -} - -# Backup system files based on user input -if [ "$1" == "--backup" ]; then - if [ "$2" = "" ]; then - echo "Error: Please specify the file or directory to backup." - exit 1 - fi - - # Perform the backup - echo "Backing up system files to extras..." - backup_to_extras "$2" - echo "Backup completed." - - # Restore system files based on user input -elif [ "$1" == "--restore" ]; then - if [ "$2" = "" ]; then - # If no specific file is provided, restore everything - restore_all_from_extras - else - # Restore a specific file or directory - echo "Restoring system files from extras..." - restore_from_extras "$2" - echo "Restore completed." - fi - -else - echo "Invalid option. Use '--backup' to backup or '--restore' to restore." -fi diff --git a/unix/utils/run_with_display.sh b/unix/utils/run_with_display.sh deleted file mode 100755 index 5f1f3a0..0000000 --- a/unix/utils/run_with_display.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -run_with_display() { - output=$("$@" 2>&1) - exit_status=$? - - if [[ $exit_status -ne 0 && ("$output" =~ "cannot open display" || "$output" =~ "DISPLAY environment variable is missing") ]]; then - DISPLAY=:0 "$@" - else - echo "$output" - return $exit_status - fi -} - -# Call this script with any command you want to run -command=$1 -shift -run_with_display "$command" "$@" - diff --git a/unix/utils/scratchpad b/unix/utils/scratchpad deleted file mode 100755 index d47dafe..0000000 --- a/unix/utils/scratchpad +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/bash - -# Created By: srdusr -# Created On: Tue 07 Mar 2023 15:06:47 PM CAT -# Project: Agnostic scratchpad/dropdown terminal that works on most window managers - -# Dependencies: wmctrl, xprop, xdo, xdotool -# NOTE: Ensure script is included in system's path and can therefore be invoked with the command 'scratchpad'. -# Furthermore make sure the terminal is using x11 as a backend in wayland to allow this to work. -# Example: wezterm.lua: enable_wayland = false, -# kitty.conf: linux_display_server x11 - -# Set the environment variables to x11 to allow working in Wayland -#export GDK_BACKEND=x11 -#export QT_QPA_PLATFORM=xcb -#export WAYLAND_DISPLAY="" -#export WINIT_UNIX_BACKEND=x11 -#export WAYLAND_DISPLAY=wayland-0 - -# Supported terminals and dropdown class -supported_terminals=("wezterm" "kitty" "alacritty") - -# Check if any supported terminal with scratchpad class is running -for term in "${supported_terminals[@]}"; do - if pgrep -f "$term.*--class scratchpad" >/dev/null; then - my_term="$term" - break - fi -done - -# If no supported terminal is running, start the first available one -if [ "$my_term" = "" ]; then - for term in "${supported_terminals[@]}"; do - if command -v "$term" >/dev/null 2>&1; then - my_term="$term" - break - fi - done - if [ "$my_term" = "" ]; then - echo "No supported terminal found." && exit 1 - fi - - # Start terminal with scratchpad class - case "$my_term" in - "wezterm") wezterm start --class scratchpad -e tmux new-session -A -s tmux -e bash & ;; - "kitty") kitty --class scratchpad tmux new-session -A -s tmux -e bash & ;; - "alacritty") alacritty --class scratchpad -e tmux new-session -A -s tmux -e bash & ;; - esac -fi - -# Get the window ID of the scratchpad terminal -id="$(xdo id -N scratchpad)" -# Get the ID of the currently focused window -focused_id="$(xdotool getwindowfocus)" - -# Get class of the currently focused window -focused_class="$(xprop -id "$focused_id" WM_CLASS 2>/dev/null | awk -F '"' '{print $4}')" - -# Toggle visible/hide and smart focus -if [ "$id" != "" ]; then - if xwininfo -id "$id" | grep "Map State: IsViewable" >/dev/null; then - if [ "$focused_id" = "$id" ] || [ "$focused_class" = "scratchpad" ]; then - # Scratchpad is focused, hide it - dimensions="$(xwininfo -id "$id" | awk '/Width:|Height:/ { printf("%s=%s;", tolower($1), $2) }')" - xdo hide "$id" 2>/dev/null - else - # Scratchpad is visible but not focused - xdotool windowactivate "$id" - xdotool windowfocus "$id" - hyprctl dispatch focuswindow scratchpad - fi - else - # Scratchpad is hidden, show and focus it - xdo show "$id" - xdotool windowsize "$id" "$(echo "$dimensions" | tr ';' ' ')" 2>/dev/null - xdotool windowactivate "$id" - xdotool windowfocus "$id" - hyprctl dispatch focuswindow scratchpad - fi -fi - -## Get the window ID of the PiP window by title -#pip_id="$(xdo id -n "Picture-in-Picture")" -# -## Toggle scratchpad terminal visibility -#if [ "$id" != "" ]; then -# if xwininfo -id "$id" | grep "Map State: IsViewable" >/dev/null; then -# # Scratchpad is visible, hide it -# dimensions="$(xwininfo -id "$id" | awk '/Width:|Height:/ { printf("%s=%s;", tolower($1), $2) }')" -# xdo hide "$id" 2>/dev/null -# else -# # Scratchpad is hidden, show it and restore dimensions -# xdo show "$id" -# xdotool windowsize "$id" "$(echo "$dimensions" | tr ';' ' ')" 2>/dev/null -# xdotool windowactivate "$id" -# xdotool windowfocus "$id" -# -# # Adjust layer based on PiP window presence -# if [ "$pip_id" != "" ]; then -# hyprctl dispatch layer "$id" 1 -# else -# hyprctl dispatch layer "$id" 0 -# fi -# -# hyprctl dispatch focuswindow scratchpad -# fi -#fi - -## Get the window ID of the scratchpad terminal -#id=$(hyprctl clients -j | jq -r '.[] | select(.class=="scratchpad").address') -# -## Toggle scratchpad terminal visibility -#if [ -n "$id" ]; then -# focused=$(hyprctl activewindow -j | jq -r '.address') -# if [ "$focused" = "$id" ]; then -# # Scratchpad is focused, minimize it -# hyprctl dispatch move "address:$id workspace silent 0" -# else -# # Show scratchpad, set above normal windows but below PiP -# hyprctl dispatch movetoworkspace current address:$id -# hyprctl dispatch focuswindow address:$id -# hyprctl dispatch layer "address:$id above" -# hyprctl dispatch focuswindow address:$id -# fi -#fi - -## Get the window ID of the PiP window by title -#pip_id=$(hyprctl clients -j | jq -r '.[] | select(.title=="Picture-in-Picture").address') -# -## Toggle scratchpad terminal visibility -#if [ -n "$id" ]; then -# focused=$(hyprctl activewindow -j | jq -r '.address') -# if [ "$focused" = "$id" ]; then -# # Scratchpad is focused, minimize it -# hyprctl dispatch move "address:$id workspace silent 0" -# else -# # Show scratchpad, set above normal windows but below PiP -# hyprctl dispatch movetoworkspace current address:$id -# hyprctl dispatch focuswindow address:$id -# if [ -n "$pip_id" ]; then -# hyprctl dispatch layer "address:$id below" -# else -# hyprctl dispatch layer "address:$id above" -# fi -# hyprctl dispatch focuswindow address:$id -# fi -#fi diff --git a/unix/utils/screenshot b/unix/utils/screenshot deleted file mode 100755 index b209574..0000000 --- a/unix/utils/screenshot +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/sh - -# === Config: directory for QEMU sockets === -QEMU_SOCK_DIR="/home/$(whoami)/virt/machines" - -# === Send 'print' key to QEMU monitor === -send_print_to_qemu() { - monitor_socket=$(find "$QEMU_SOCK_DIR" -maxdepth 1 -type s -name '*-monitor.socket' | head -n1) - if [ "$monitor_socket" = "" ]; then - echo "No QEMU monitor socket found." - return 1 - fi - echo "Using QEMU monitor socket: $monitor_socket" - if ! printf "sendkey print\n" | socat - UNIX-CONNECT:"$monitor_socket"; then - echo "Failed to send key via socat." - return 1 - fi - echo "Sent 'sendkey print' to QEMU successfully." - return 0 -} - -# === Detect if current window is QEMU (X11 only) === -if [ "$DISPLAY" != "" ] && command -v xprop >/dev/null 2>&1; then - win_id=$(xprop -root _NET_ACTIVE_WINDOW | awk -F' ' '{print $5}') - class=$(xprop -id "$win_id" WM_CLASS 2>/dev/null | awk -F'"' '{print $4}') - if [ "$class" = "qemu-system-x86_64" ]; then - send_print_to_qemu && exit 0 - # if sending fails, optionally fallback or exit anyway - exit 1 - fi -fi -#if command -v hyprctl >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then -# focused_class="$(hyprctl activewindow -j | jq -r '.class' 2>/dev/null)" -# if [ "$focused_class" = "qemu-system-x86_64" ]; then -# send_print_to_qemu && exit 0 -# fi -#fi - -DIR="$HOME/pictures/screenshots" -OUTPUT_DIR="$HOME/documents/ocr_output" - -# Create the directories if they don't exist -[ ! -d "$DIR" ] && mkdir -pv "$DIR" -[ ! -d "$OUTPUT_DIR" ] && mkdir -pv "$OUTPUT_DIR" - -file="$DIR/screenshot_$(date '+%Y-%m-%d_%H-%M-%S').png" -text_file="$OUTPUT_DIR/ocr_output_$(date '+%Y-%m-%d_%H-%M-%S')" - -copy_to_clipboard() { - if [ "$WAYLAND_DISPLAY" != "" ]; then - wl-copy <"$1" - elif [ "$DISPLAY" != "" ]; then - xclip -selection clipboard -i <"$1" - else - echo "No display server detected. Cannot copy to clipboard." - return 1 - fi -} - -case "$1" in -screen) grim "$file" ;; -output) slurp -o -r | grim -g - "$file" ;; -area) slurp | grim -g - "$file" ;; -output-area) slurp -o | grim -g - "$file" ;; -ocr) slurp | grim -g - "$file" && tesseract "$file" "$text_file" ;; -ocr-clipboard) - slurp | grim -g - "$file" && tesseract "$file" "$text_file" - if [ -f "$text_file.txt" ]; then - copy_to_clipboard "$text_file.txt" - CLIP_STATUS=$? - if [ "$CLIP_STATUS" -eq 0 ]; then - command rm -f "$text_file.txt" - notify-send -t 10000 --app-name "Screenshot" "OCR to Clipboard" "Text copied to clipboard." - echo "OCR output copied to clipboard and file deleted." - else - notify-send -t 10000 --app-name "Screenshot" "Clipboard Copy Failed" "Failed to copy text to clipboard." - echo "Failed to copy text to clipboard." - fi - else - notify-send -t 10000 --app-name "Screenshot" "OCR Error" "OCR process failed." - exit 1 - fi - ;; -*) - echo "Invalid argument" - notify-send -t 10000 --app-name "Screenshot" "Screenshot" "Something went wrong." - exit 1 - ;; -esac - -if [ "$1" = "ocr" ]; then - if [ -f "$text_file" ]; then - notify-send -t 10000 --app-name "Screenshot" "OCR Complete" "Text saved to $text_file" - echo "OCR output saved to: $text_file" - else - notify-send -t 10000 --app-name "Screenshot" "OCR Error" "OCR process failed." - exit 1 - fi -else - notify-send -t 10000 --app-name "Screenshot" "Screenshot" "Saved as $file" - echo "$file" -fi diff --git a/unix/utils/sendkeys.awk b/unix/utils/sendkeys.awk deleted file mode 100755 index 16a3fa9..0000000 --- a/unix/utils/sendkeys.awk +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env awk -f -# -# AWK script to send multiple `sendkey` commands to a QEMU virtual machine. -# It writes at a rate of roughly 40 keys per second, due to lower delays -# resulting in garbage output. -# -# It makes use of a TCP client created by an external utility, such as OpenBSD -# Netcat, to interact with QEMU's monitor and send a stream of `sendkey` -# commands. This is a practical way to transfer a small file or to script -# interactions with a terminal user interface. - -BEGIN { - # Set default delay if not provided via command-line args - if (!delay) { - delay = 0.025 - } - - # Define key mappings for common characters and symbols - key["#"] = "backspace" - key[" "] = "tab" - key[" "] = "spc" - key["!"] = "shift-1" - key["\""] = "shift-apostrophe" - key["#"] = "shift-3" - key["$"] = "shift-4" - key["%"] = "shift-5" - key["&"] = "shift-7" - key["'"] = "apostrophe" - key["("] = "shift-9" - key[")"] = "shift-0" - key["*"] = "shift-8" - key["+"] = "shift-equal" - key[","] = "comma" - key["-"] = "minus" - key["."] = "dot" - key["/"] = "slash" - key[":"] = "shift-semicolon" - key[";"] = "semicolon" - key["<"] = "shift-comma" - key["="] = "equal" - key[">"] = "shift-dot" - key["?"] = "shift-slash" - key["@"] = "shift-2" - - # Map numbers - for (i = 48; i < 48 + 10; ++i) { - number = sprintf("%c", i) - key[number] = number - } - - # Map letters A-Z, including shift - for (i = 65; i < 65 + 26; ++i) { - key[sprintf("%c", i)] = sprintf("shift-%c", i + 32) - } - - # Other symbols - key["["] = "bracket_left" - key["\\"] = "backslash" - key["]"] = "bracket_right" - key["^"] = "shift-6" - key["_"] = "shift-minus" - key["`"] = "grave_accent" - key["{"] = "shift-bracket_left" - key["|"] = "shift-backslash" - key["}"] = "shift-bracket_right" - key["~"] = "shift-grave_accent" - key[""] = "delete" - - # Handle Super and Caps Lock key mappings (for remapping Caps to Super) - key["capslock"] = "super" - key["super"] = "super" - - # Handle other keys if needed -} - -{ - split($0, chars, "") - for (i = 1; i <= length($0); i++) { - # Print sendkey command for the character, mapping it through the key[] array - if (key[chars[i]] != "") { - printf("sendkey %s\n", key[chars[i]]) - } - system("sleep " delay) # Sleep for the defined delay - } - printf "sendkey ret\n" # Send "return" (enter) key at the end -} diff --git a/unix/utils/sext b/unix/utils/sext deleted file mode 100755 index b120929..0000000 --- a/unix/utils/sext +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -#Sext (Shutdown Exit) -# List of package managers to check for -package_managers=("emerge" "apt" "dnf" "pacman" "zypper") - -# Set how often to check (in seconds) -check_interval=30 - -# Check if any package manager is running -is_package_manager_running() { - for pm in "${package_managers[@]}"; do - if pgrep -x "$pm" >/dev/null; then - return 0 # Return 0 (true) if any package manager is running - fi - done - return 1 # Return 1 (false) if no package manager is running -} - -# Safely shutdown the system -safe_shutdown() { - # Try using shutdown without sudo first - if shutdown -h now; then - echo "Shutdown initiated successfully using 'shutdown'." - # If shutdown fails, try using poweroff - elif poweroff; then - echo "Shutdown initiated successfully using 'poweroff'." - # If poweroff fails, try using sudo poweroff - elif sudo poweroff; then - echo "Shutdown initiated successfully with 'sudo poweroff'." - # If both shutdown and poweroff fail, try with sudo shutdown - elif sudo shutdown -h now; then - echo "Shutdown initiated successfully with 'sudo shutdown'." - else - echo "Shutdown command failed. Please check your system configuration." - fi -} - -# Loop until no package manager process is running -while is_package_manager_running; do - echo "Package manager is still running. Checking again in $check_interval seconds..." - sleep "$check_interval" -done - -# Once the process completes, initiate a safe shutdown -echo "Package manager has finished. Attempting to shutdown..." -safe_shutdown diff --git a/unix/utils/track-books.sh b/unix/utils/track-books.sh deleted file mode 100755 index f13add8..0000000 --- a/unix/utils/track-books.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Created By: srdusr -# Created On: Wed 25 Oct 2023 13:45:52 CAT -# Project: Simple script to track most recent books opened, mainly for neovim usage. - -# Dependencies: inotify-tools - -books_directory="$HOME/documents/books" -recent_books_file="$HOME/.config/nvim/tmp/recent_books.txt" - -inotifywait -m -e CREATE -e OPEN -r "$books_directory" | - while read -r path action file; do - if [[ $file == *.pdf || $file == *.epub ]]; then - echo "$path/$file" >>"$recent_books_file" - # Remove duplicates and overwrite the recent_books_file - sort -u -o "$recent_books_file" "$recent_books_file" - fi - done diff --git a/unix/utils/umnt b/unix/utils/umnt deleted file mode 100755 index 6d9b788..0000000 --- a/unix/utils/umnt +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# unmount disk -set -e -. ~/etc/colors/current - -lsblk -Po NAME,SIZE,MOUNTPOINT,FSTYPE,LABEL | while read -r a; do - eval "$a" - - [ "$MOUNTPOINT" ] && ! grep -iq "\s$MOUNTPOINT\s" /etc/fstab && - printf "%-4s:%s:%s:<- %s\n" \ - "$NAME" \ - "$SIZE" \ - "${LABEL:-unnamed}" \ - "${MOUNTPOINT//$HOME/\~}" - - done | column -ts':' -o' ' | menu -p unmount | { - read -r NAME _ - eval "$(lsblk -Po LABEL,MOUNTPOINT "/dev/$NAME")" - notify-send summary "<span color='#$red'>$NAME: $LABEL</span>\n${MOUNTPOINT/$HOME/\~}" - sudo umount "$MOUNTPOINT" - sudo rmdir "$HOME/dev/$NAME" || : -} diff --git a/unix/utils/waypipe_app b/unix/utils/waypipe_app deleted file mode 100755 index a8520bc..0000000 --- a/unix/utils/waypipe_app +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# Usage: ./waypipe_app user@remote <app> -# Example: ./waypipe_app user@remote gedit - -if [ $# -lt 2 ]; then - echo "Usage: $0 user@remote <app> [args...]" - exit 1 -fi - -REMOTE=$1 -shift -APP="$@" - -# Run the app remotely, forward display over SSH with waypipe -waypipe ssh "$REMOTE" $APP diff --git a/unix/utils/wayvnc_session b/unix/utils/wayvnc_session deleted file mode 100755 index 1f2f30b..0000000 --- a/unix/utils/wayvnc_session +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# Usage: ./wayvnc_session [address] [port] -# Default: 0.0.0.0 5900 - -ADDR=${1:-0.0.0.0} -PORT=${2:-5900} - -echo "Starting Wayland VNC server on $ADDR:$PORT" -wayvnc $ADDR $PORT diff --git a/unix/utils/window_manager_name.sh b/unix/utils/window_manager_name.sh deleted file mode 100755 index cfff9ee..0000000 --- a/unix/utils/window_manager_name.sh +++ /dev/null @@ -1,29 +0,0 @@ -#! /bin/bash - - -windowManagerName () { - local window=$( - xprop -root -notype - ) - - local identifier=$( - echo "${window}" | - awk '$1=="_NET_SUPPORTING_WM_CHECK:"{print $5}' - ) - - local attributes=$( - xprop -id "${identifier}" -notype -f _NET_WM_NAME 8t - ) - - local name=$( - echo "${attributes}" | - grep "_NET_WM_NAME = " | - cut --delimiter=' ' --fields=3 | - cut --delimiter='"' --fields=2 - ) - - echo "${name}" -} - - -windowManagerName diff --git a/unix/utils/xtouch b/unix/utils/xtouch deleted file mode 100755 index a5eb23b..0000000 --- a/unix/utils/xtouch +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -check_valid() { - if [ -f "$1" ]; then - echo "The file "$1" already exists!" - exit 1 - fi -} - -create_script() { - touch "$1" - chmod +x "$1" - echo "$0: $2 script file $1 created with exec permissions" - echo -e '#!/usr/bin/env '"$2" > "$1" -} - -usage() { - echo -e "Quickly create executable script\n" - echo "Usage:" - echo " xtouch [ -w FILE LANG ]" - echo -e " xtouch ( -h | --help )\n" - echo "Arguments:" - echo "FILE Name to give the scripts" - echo -e "LANG Language in which the script will be written\n" - echo "Options:" - echo " -w FILE LANG Creates a <LANG> executable script file named <FILE>." - echo " -h --help Show this screen." -} - -case "$1" in - '-w') - check_valid "$2" - create_script "$2" "$3" - ;; - *) - usage - ;; -esac diff --git a/unix/virt/checksum.sh b/unix/virt/checksum.sh deleted file mode 100755 index adb6a24..0000000 --- a/unix/virt/checksum.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# Check if the correct number of arguments are provided -if [[ $# -ne 2 ]]; then - echo "Usage: checksum <file> <website>" - exit 1 -fi - -FILE=$1 -CHECKSUM_PAGE=$2 - -# Fetch the HTML content of the page -HTML_CONTENT=$(curl -s "$CHECKSUM_PAGE") - -# Try searching for checksums with a more targeted approach, like matching a checksum pattern or look for files with checksum labels -CHECKSUM=$(echo "$HTML_CONTENT" | grep -oP '([a-f0-9]{64})' | head -n 1) # Try specifically looking for SHA256 checksum patterns - -# Check if any checksum was found -if [[ -z "$CHECKSUM" ]]; then - echo "Checksum not found on the page." - exit 1 -fi - -# Calculate the checksum of the file locally -LOCAL_CHECKSUM=$(sha256sum "$FILE" | awk '{print $1}') - -echo "Local checksum: $LOCAL_CHECKSUM" -echo "Remote checksum: $CHECKSUM" - -# Compare the local checksum with the one from the website -if [[ "$LOCAL_CHECKSUM" == "$CHECKSUM" ]]; then - echo "The checksums match! The file is verified." - -else - echo "The checksums do not match. The file may be corrupted or tampered with." -fi diff --git a/unix/virt/dos.sh b/unix/virt/dos.sh deleted file mode 100755 index 0b50c4b..0000000 --- a/unix/virt/dos.sh +++ /dev/null @@ -1,998 +0,0 @@ -#!/usr/bin/env bash - -# Set variables -HOST_DIR="virt" -VM_NAME="dos" -VM_SIZE="80G" # Disk size in GB -VM_RAM="8G" # RAM size -VM_CPU="6" # Number of virtual CPUs -CORES=$((VM_CPU / 2)) -THREADS_PER_CORE=2 -SOCKETS=1 - -VM_DIR="$HOST_DIR/machines" -IMAGE_DIR="$HOST_DIR/images" -WIN_ISO_DIR="${IMAGE_DIR}/${VM_NAME}" # Directory for Windows ISO -VM_DIR="$WIN_ISO_DIR" -SOCKET_DIR="$VM_DIR" -SHARED_DIR="${HOST_DIR}/shared" -FIRMWARE_DIR="${HOST_DIR}/firmware" -TPM_DIR="$WIN_ISO_DIR" -TPM_SOCKET="${WIN_ISO_DIR}/${VM_NAME}.swtpm-sock" -GUEST_PORT=22 -QCOW2_FILE="${VM_DIR}/${VM_NAME}.qcow2" -RAW_FILE="${VM_DIR}/${VM_NAME}.raw" - -# Anti-detection: Generate realistic hardware identifiers -REAL_MAC="00:1A:2B:3C:4D:5E" # Example Dell MAC - replace with your choice -REAL_SERIAL="$(openssl rand -hex 8 | tr '[:lower:]' '[:upper:]')" -REAL_UUID="$(uuidgen)" -REAL_VENDOR="Dell Inc." -REAL_PRODUCT="OptiPlex 7090" -REAL_VERSION="01" -REAL_FAMILY="OptiPlex" - -# Try to find an available host port starting from 22220 -HOST_PORT_START=22220 -HOST_PORT_END=22300 - -for ((port = HOST_PORT_START; port <= HOST_PORT_END; port++)); do - if ! ss -tuln | grep -q ":$port\b"; then - HOST_PORT=$port - echo "Using available port: $HOST_PORT" - break - fi -done - -if [[ $port -gt $HOST_PORT_END ]]; then - echo "Error: No available ports found between $HOST_PORT_START and $HOST_PORT_END" >&2 - exit 1 -fi - -# Set SMP configuration -SMP_CONFIG="cores=$CORES,threads=$THREADS_PER_CORE,sockets=$SOCKETS" - -# Create necessary directories -mkdir -p "${HOME}/${HOST_DIR}" -mkdir -p "$IMAGE_DIR" "$SHARED_DIR" "$FIRMWARE_DIR" -mkdir -p "$WIN_ISO_DIR" "$VM_DIR" -mkdir -p "${WIN_ISO_DIR}/unattended" - -# Define ISO paths and URLs -ISO_VIRTIO="${WIN_ISO_DIR}/virtio-win.iso" -ISO_UNATTENDED="${WIN_ISO_DIR}/unattended.iso" - -# Find Windows ISO with flexible pattern matching -find_windows_iso() { - # Check if directory exists - if [[ ! -d "$WIN_ISO_DIR" ]]; then - mkdir -p "$WIN_ISO_DIR" - fi - - # Try to find any Windows ISO using case-insensitive patterns - local found_iso - found_iso=$(find "$WIN_ISO_DIR" -maxdepth 1 -type f \( \ - -iname "*win11*.iso" -o \ - -iname "*win*11*.iso" -o \ - -iname "Win*.iso" -o \ - -iname "Win11*.iso" -o \ - -iname "Win*11*.iso" -o \ - -iname "*windows*11*.iso" -o \ - -iname "*windows11*.iso" \ - \) -exec stat --format="%Y %n" {} \; | sort -n | tail -n 1 | cut -d' ' -f2-) - - if [[ -n "$found_iso" && -f "$found_iso" ]]; then - echo "$found_iso" - return 0 - fi - - return 1 -} - -# Define download URLs -VIRTIO_ISO_URL="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" - -# Print colored messages -print_info() { echo -e "\033[1;34m[INFO]\033[0m $1" >&2; } -print_success() { echo -e "\033[1;32m[SUCCESS]\033[0m $1" >&2; } -print_warning() { echo -e "\033[1;33m[WARNING]\033[0m $1" >&2; } -print_error() { echo -e "\033[1;31m[ERROR]\033[0m $1" >&2; } - -# Helper: verify file integrity -verify_file() { - local file="$1" - local expected_sha256="$2" - - if [[ ! -f "$file" ]]; then - return 1 - fi - - if [[ -n "$expected_sha256" ]]; then - local actual_sha256 - actual_sha256=$(sha256sum "$file" | cut -d' ' -f1) - if [[ "$actual_sha256" != "$expected_sha256" ]]; then - print_error "File integrity check failed for $file" - return 1 - fi - fi - - return 0 -} - -# Helper: download file with verification -download_file() { - local url="$1" - local dest="$2" - local expected_sha256="$3" - local allow_failure="$4" - - # Check if file exists and is valid - if [[ -f "$dest" ]]; then - if verify_file "$dest" "$expected_sha256"; then - print_info "File $dest already exists and verified." - return 0 - else - print_warning "File $dest exists but failed verification. Redownloading..." - rm -f "$dest" - fi - fi - - print_info "Downloading $url..." - if ! curl -fL --progress-bar -o "$dest" "$url"; then - print_error "Failed to download $url." - if [[ "$allow_failure" != "true" ]]; then - return 1 - fi - else - # Verify downloaded file - if ! verify_file "$dest" "$expected_sha256"; then - print_error "Downloaded file failed verification" - rm -f "$dest" - return 1 - fi - print_success "Successfully downloaded and verified $dest" - fi - - return 0 -} - -# Handle curl errors -handle_curl_error() { - local exit_code=$1 - case $exit_code in - 6) print_error "Couldn't resolve host" ;; - 7) print_error "Failed to connect to host" ;; - 22) print_error "HTTP page not retrieved (404, etc.)" ;; - 28) print_error "Operation timeout" ;; - *) print_error "Curl failed with exit code $exit_code" ;; - esac -} - -# Download Windows 11 ISO using Microsoft's API -download_windows_iso() { - local windows_version="11" # Default to Windows 11 - local language="English (United States)" # Default language - - # Parse arguments if provided - if [[ -n "$1" ]]; then - windows_version="$1" - fi - - print_info "Attempting to download Windows $windows_version ISO from Microsoft..." - - # Set required variables - local user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0" - local session_id="$(uuidgen)" - local profile="606624d44113" - local url="https://www.microsoft.com/en-us/software-download/windows$windows_version" - - # Add ISO to URL for Windows 10 - case "$windows_version" in - 10) url="${url}ISO" ;; - esac - - # Step 1: Get download page HTML - print_info "Fetching download page: $url" - local iso_download_page_html - iso_download_page_html="$(curl --disable --silent --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url")" || { - handle_curl_error $? - print_error "Failed to fetch the download page. Please download Windows $windows_version ISO manually from $url" - return 1 - } - - # Step 2: Extract Product Edition ID - print_info "Getting Product Edition ID..." - local product_edition_id - product_edition_id="$(echo "$iso_download_page_html" | grep -Eo '<option value="[0-9]+">Windows' | cut -d '"' -f 2 | head -n 1 | tr -cd '0-9' | head -c 16)" - - if [[ -z "$product_edition_id" ]]; then - print_error "Failed to extract product edition ID." - print_error "Please download Windows $windows_version ISO manually from $url" - return 1 - fi - - print_success "Product Edition ID: $product_edition_id" - - # Step 3: Register session ID - print_info "Registering session ID: $session_id" - curl --disable --silent --output /dev/null --user-agent "$user_agent" \ - --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 \ - --http1.1 -- "https://vlscppe.microsoft.com/tags?org_id=y6jn8c31&session_id=$session_id" || { - print_error "Failed to register session ID." - return 1 - } - - # Step 4: Get language SKU ID - print_info "Getting language SKU ID..." - local language_skuid_table_json - language_skuid_table_json="$(curl --disable -s --fail --max-filesize 100K --proto =https --tlsv1.2 --http1.1 \ - "https://www.microsoft.com/software-download-connector/api/getskuinformationbyproductedition?profile=${profile}&ProductEditionId=${product_edition_id}&SKU=undefined&friendlyFileName=undefined&Locale=en-US&sessionID=${session_id}")" || { - handle_curl_error $? - print_error "Failed to get language SKU information." - return 1 - } - - # Extract SKU ID for selected language - local sku_id - - # Try with jq if available (more reliable) - if command -v jq >/dev/null 2>&1; then - sku_id="$(echo "$language_skuid_table_json" | jq -r '.Skus[] | select(.LocalizedLanguage=="'"$language"'" or .Language=="'"$language"'").Id')" - else - # Fallback to grep/cut if jq not available - sku_id="$(echo "$language_skuid_table_json" | grep -o '"Id":"[^"]*","Language":"'"$language"'"' | cut -d'"' -f4)" - - if [[ -z "$sku_id" ]]; then - # Try alternative extraction method - sku_id="$(echo "$language_skuid_table_json" | grep -o '"LocalizedLanguage":"'"$language"'","Id":"[^"]*"' | cut -d'"' -f6)" - fi - fi - - if [[ -z "$sku_id" ]]; then - print_error "Failed to extract SKU ID for $language." - return 1 - fi - - print_success "SKU ID: $sku_id" - - # Step 5: Get ISO download link - print_info "Getting ISO download link..." - local iso_download_link_json - iso_download_link_json="$(curl --disable -s --fail --referer "$url" \ - "https://www.microsoft.com/software-download-connector/api/GetProductDownloadLinksBySku?profile=${profile}&productEditionId=undefined&SKU=${sku_id}&friendlyFileName=undefined&Locale=en-US&sessionID=${session_id}")" - - local failed=0 - - if [[ -z "$iso_download_link_json" ]]; then - print_error "Microsoft servers gave an empty response to the download request." - failed=1 - fi - - if echo "$iso_download_link_json" | grep -q "Sentinel marked this request as rejected."; then - print_error "Microsoft blocked the automated download request based on your IP address." - failed=1 - fi - - if [[ "$failed" -eq 1 ]]; then - print_warning "Please manually download the Windows $windows_version ISO using a web browser from: $url" - print_warning "Save the downloaded ISO to: $WIN_ISO_DIR" - return 1 - fi - - # Extract 64-bit ISO download URL - local iso_download_link - - # Try with jq if available - if command -v jq >/dev/null 2>&1; then - iso_download_link="$(echo "$iso_download_link_json" | jq -r '.ProductDownloadOptions[].Uri' | grep x64 | head -n 1)" - else - # Fallback to grep/cut if jq not available - iso_download_link="$(echo "$iso_download_link_json" | grep -o '"Uri":"[^"]*x64[^"]*"' | cut -d'"' -f4 | head -n 1)" - fi - - if [[ -z "$iso_download_link" ]]; then - print_error "Failed to extract the download link from Microsoft's response." - print_warning "Manually download the Windows $windows_version ISO using a web browser from: $url" - return 1 - fi - - print_success "Got download link: ${iso_download_link%%\?*}" - - # Extract filename from URL - local file_name="$(echo "$iso_download_link" | cut -d'?' -f1 | rev | cut -d'/' -f1 | rev)" - - # If filename couldn't be extracted, use default - if [[ -z "$file_name" || "$file_name" == "$iso_download_link" ]]; then - file_name="windows-$windows_version.iso" - fi - - # Step 6: Download the ISO - print_info "Downloading Windows $windows_version ISO to $WIN_ISO_DIR/$file_name. This may take a while..." - - # Direct curl download - curl --disable --progress-bar --fail --location --proto '=https' --tlsv1.2 --http1.1 \ - --retry 3 --retry-delay 3 --connect-timeout 30 \ - --output "$WIN_ISO_DIR/$file_name" "$iso_download_link" || { - handle_curl_error $? - return 1 - } - - if [[ $? -ne 0 ]]; then - print_error "Failed to download the Windows $windows_version ISO." - return 1 - fi - - print_success "Successfully downloaded Windows $windows_version ISO to $WIN_ISO_DIR/$file_name" - - # Return the downloaded filename so calling code can use it - echo "$file_name" - return 0 -} - -# Create unattended installation ISO with proper Windows 11 bypass -create_unattended_iso() { - print_info "Creating unattended installation ISO..." - - # Create enhanced autounattend.xml with Windows 11 TPM/Secure Boot bypass - if [ ! -f "$WIN_ISO_DIR/unattended/autounattend.xml" ]; then - print_info "Creating enhanced autounattend.xml with Windows 11 bypass..." - mkdir -p "$WIN_ISO_DIR/unattended" - cat >"$WIN_ISO_DIR/unattended/autounattend.xml" <<'EOF' -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend"> - <settings pass="windowsPE"> - <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <SetupUILanguage> - <UILanguage>en-US</UILanguage> - </SetupUILanguage> - <InputLocale>en-US</InputLocale> - <SystemLocale>en-US</SystemLocale> - <UILanguage>en-US</UILanguage> - <UILanguageFallback>en-US</UILanguageFallback> - <UserLocale>en-US</UserLocale> - </component> - <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <DiskConfiguration> - <Disk wcm:action="add"> - <CreatePartitions> - <CreatePartition wcm:action="add"> - <Order>1</Order> - <Type>Primary</Type> - <Size>100</Size> - </CreatePartition> - <CreatePartition wcm:action="add"> - <Order>2</Order> - <Type>EFI</Type> - <Size>100</Size> - </CreatePartition> - <CreatePartition wcm:action="add"> - <Order>3</Order> - <Type>MSR</Type> - <Size>16</Size> - </CreatePartition> - <CreatePartition wcm:action="add"> - <Order>4</Order> - <Type>Primary</Type> - <Extend>true</Extend> - </CreatePartition> - </CreatePartitions> - <ModifyPartitions> - <ModifyPartition wcm:action="add"> - <Order>1</Order> - <PartitionID>1</PartitionID> - <Label>WINRE</Label> - <Format>NTFS</Format> - <TypeID>DE94BBA4-06D1-4D40-A16A-BFD50179D6AC</TypeID> - </ModifyPartition> - <ModifyPartition wcm:action="add"> - <Order>2</Order> - <PartitionID>2</PartitionID> - <Label>System</Label> - <Format>FAT32</Format> - </ModifyPartition> - <ModifyPartition wcm:action="add"> - <Order>3</Order> - <PartitionID>3</PartitionID> - </ModifyPartition> - <ModifyPartition wcm:action="add"> - <Order>4</Order> - <PartitionID>4</PartitionID> - <Label>Windows</Label> - <Format>NTFS</Format> - </ModifyPartition> - </ModifyPartitions> - <DiskID>0</DiskID> - <WillWipeDisk>true</WillWipeDisk> - </Disk> - </DiskConfiguration> - <ImageInstall> - <OSImage> - <InstallTo> - <DiskID>0</DiskID> - <PartitionID>4</PartitionID> - </InstallTo> - <InstallToAvailablePartition>false</InstallToAvailablePartition> - <WillShowUI>OnError</WillShowUI> - <InstallFrom> - <MetaData wcm:action="add"> - <Key>/IMAGE/INDEX</Key> - <Value>6</Value> - </MetaData> - </InstallFrom> - </OSImage> - </ImageInstall> - <UserData> - <AcceptEula>true</AcceptEula> - <FullName>Windows User</FullName> - <Organization>Windows</Organization> - <ProductKey> - <WillShowUI>Never</WillShowUI> - </ProductKey> - </UserData> - <!-- Windows 11 Requirements Bypass --> - <RunSynchronous> - <RunSynchronousCommand wcm:action="add"> - <Order>1</Order> - <Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassTPMCheck /t REG_DWORD /d 1 /f</Path> - </RunSynchronousCommand> - <RunSynchronousCommand wcm:action="add"> - <Order>2</Order> - <Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassSecureBootCheck /t REG_DWORD /d 1 /f</Path> - </RunSynchronousCommand> - <RunSynchronousCommand wcm:action="add"> - <Order>3</Order> - <Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassRAMCheck /t REG_DWORD /d 1 /f</Path> - </RunSynchronousCommand> - <RunSynchronousCommand wcm:action="add"> - <Order>4</Order> - <Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassStorageCheck /t REG_DWORD /d 1 /f</Path> - </RunSynchronousCommand> - <RunSynchronousCommand wcm:action="add"> - <Order>5</Order> - <Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassCPUCheck /t REG_DWORD /d 1 /f</Path> - </RunSynchronousCommand> - </RunSynchronous> - <EnableFirewall>false</EnableFirewall> - <EnableNetwork>true</EnableNetwork> - </component> - </settings> - <settings pass="specialize"> - <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <InputLocale>en-US</InputLocale> - <SystemLocale>en-US</SystemLocale> - <UILanguage>en-US</UILanguage> - <UILanguageFallback>en-US</UILanguageFallback> - <UserLocale>en-US</UserLocale> - </component> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <ComputerName>DESKTOP-PC</ComputerName> - <TimeZone>UTC</TimeZone> - </component> - <component name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <SkipAutoActivation>true</SkipAutoActivation> - </component> - </settings> - <settings pass="oobeSystem"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <AutoLogon> - <Password> - <Value>password</Value> - <PlainText>true</PlainText> - </Password> - <LogonCount>1</LogonCount> - <Username>Administrator</Username> - <Enabled>true</Enabled> - </AutoLogon> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Home</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - <SkipMachineOOBE>true</SkipMachineOOBE> - <SkipUserOOBE>true</SkipUserOOBE> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>password</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - <LocalAccounts> - <LocalAccount wcm:action="add"> - <Password> - <Value>password</Value> - <PlainText>true</PlainText> - </Password> - <Name>User</Name> - <Group>Administrators</Group> - <DisplayName>User</DisplayName> - </LocalAccount> - </LocalAccounts> - </UserAccounts> - <!-- Additional Windows 11 bypass commands --> - <FirstLogonCommands> - <SynchronousCommand wcm:action="add"> - <Order>1</Order> - <CommandLine>reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v NoAutoUpdate /t REG_DWORD /d 1 /f</CommandLine> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <Order>2</Order> - <CommandLine>reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f</CommandLine> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <Order>3</Order> - <CommandLine>powershell -Command "Set-ExecutionPolicy Unrestricted -Force"</CommandLine> - </SynchronousCommand> - </FirstLogonCommands> - </component> - </settings> -</unattend> -EOF - fi - - # Create the unattended ISO - if command -v genisoimage >/dev/null 2>&1; then - print_info "Creating unattended ISO using genisoimage..." - genisoimage -J -r -o "$WIN_ISO_DIR/unattended.iso" "$WIN_ISO_DIR/unattended" 2>/dev/null - return $? - elif command -v mkisofs >/dev/null 2>&1; then - print_info "Creating unattended ISO using mkisofs..." - mkisofs -J -r -o "$WIN_ISO_DIR/unattended.iso" "$WIN_ISO_DIR/unattended" 2>/dev/null - return $? - elif command -v xorriso >/dev/null 2>&1; then - print_info "Creating unattended ISO using xorriso..." - xorriso -as genisoimage -J -r -o "$WIN_ISO_DIR/unattended.iso" "$WIN_ISO_DIR/unattended" 2>/dev/null - return $? - else - print_warning "No ISO creation tool found (genisoimage, mkisofs, or xorriso)" - print_warning "Installing genisoimage..." - if command -v apt-get >/dev/null 2>&1; then - sudo apt-get update && sudo apt-get install -y genisoimage - elif command -v yum >/dev/null 2>&1; then - sudo yum install -y genisoimage - elif command -v pacman >/dev/null 2>&1; then - sudo pacman -S --noconfirm cdrtools - fi - - # Try again after installation - if command -v genisoimage >/dev/null 2>&1; then - print_info "Creating unattended ISO using newly installed genisoimage..." - genisoimage -J -r -o "$WIN_ISO_DIR/unattended.iso" "$WIN_ISO_DIR/unattended" 2>/dev/null - return $? - else - print_error "Failed to install ISO creation tools" - return 1 - fi - fi -} - -# Download or locate essential files -prepare_files() { - # Find Windows ISO - WINDOWS_ISO_PATH=$(find_windows_iso | tail -n 1 | xargs) - local iso_found=false - - # Check if we found a valid ISO - if [[ -n "$WINDOWS_ISO_PATH" && -f "$WINDOWS_ISO_PATH" ]]; then - print_success "Using Windows ISO: $WINDOWS_ISO_PATH" - iso_found=true - else - print_warning "Windows ISO not found, attempting to download..." - if download_windows_iso; then - # Check again after download attempt - WINDOWS_ISO_PATH=$(find_windows_iso | tail -n 1 | xargs) - if [[ -n "$WINDOWS_ISO_PATH" && -f "$WINDOWS_ISO_PATH" ]]; then - print_success "Using downloaded Windows ISO: $WINDOWS_ISO_PATH" - iso_found=true - fi - fi - fi - - # If we still don't have an ISO, exit - if [[ "$iso_found" != "true" ]]; then - print_error "Could not find or download Windows ISO" - print_info "Please place your Windows ISO file in: $WIN_ISO_DIR" - exit 1 - fi - - # Download VirtIO drivers if missing (optional for stealth mode) - if [[ ! -f "$ISO_VIRTIO" ]]; then - print_info "VirtIO drivers ISO not found, downloading (for fallback)..." - download_file "$VIRTIO_ISO_URL" "$ISO_VIRTIO" "" "true" - else - print_success "VirtIO drivers ISO already exists: $ISO_VIRTIO" - fi - - # Create unattended ISO if it doesn't exist - if [[ ! -f "$ISO_UNATTENDED" ]]; then - create_unattended_iso - if [[ $? -eq 0 ]]; then - print_success "Created unattended ISO: $ISO_UNATTENDED" - else - print_error "Failed to create unattended ISO" - exit 1 - fi - else - print_success "Unattended ISO already exists: $ISO_UNATTENDED" - fi -} - -# Locate OVMF firmware files -locate_ovmf() { - OVMF_DIRS=( - "/usr/share/OVMF" - "/usr/share/qemu" - "/usr/lib/qemu" - "/usr/share/edk2" - "/usr/lib/edk2" - "/usr/share/edk2/ovmf" - "/usr/share/edk2-ovmf" - "/usr/share/qemu/edk2-x86_64-code.fd" - ) - - OVMF_CODE="" - OVMF_VARS="" - - for dir in "${OVMF_DIRS[@]}"; do - if [[ -f "$dir" ]]; then - # Handle direct file paths - if [[ "$dir" == *"code.fd" ]]; then - OVMF_CODE="$dir" - OVMF_VARS="$(dirname "$dir")/edk2-x86_64-vars.fd" - fi - elif [[ -d "$dir" ]]; then - # Handle directories - [[ -z "$OVMF_CODE" ]] && OVMF_CODE=$(find "$dir" -type f -name "OVMF_CODE.fd" -o -name "edk2-x86_64-code.fd" 2>/dev/null | head -n 1) - [[ -z "$OVMF_VARS" ]] && OVMF_VARS=$(find "$dir" -type f -name "OVMF_VARS.fd" -o -name "edk2-x86_64-vars.fd" 2>/dev/null | head -n 1) - fi - [[ -n "$OVMF_CODE" && -n "$OVMF_VARS" ]] && break - done - - # Try package-specific locations - if [[ -z "$OVMF_CODE" || -z "$OVMF_VARS" ]]; then - # Ubuntu/Debian locations - [[ -z "$OVMF_CODE" ]] && OVMF_CODE="/usr/share/OVMF/OVMF_CODE_4M.fd" - [[ -z "$OVMF_VARS" && -f "/usr/share/OVMF/OVMF_VARS_4M.fd" ]] && OVMF_VARS="/usr/share/OVMF/OVMF_VARS_4M.fd" - - # Arch Linux locations - [[ -z "$OVMF_CODE" ]] && OVMF_CODE="/usr/share/edk2-ovmf/x64/OVMF_CODE.fd" - [[ -z "$OVMF_VARS" && -f "/usr/share/edk2-ovmf/x64/OVMF_VARS.fd" ]] && OVMF_VARS="/usr/share/edk2-ovmf/x64/OVMF_VARS.fd" - fi - - # Ensure a writable copy of OVMF_VARS.fd - local original_ovmf_vars="$OVMF_VARS" - OVMF_VARS="$FIRMWARE_DIR/OVMF_VARS.fd" - - if [[ ! -f "$OVMF_VARS" && -f "$original_ovmf_vars" ]]; then - print_info "Copying OVMF_VARS.fd to $OVMF_VARS" - cp "$original_ovmf_vars" "$OVMF_VARS" 2>/dev/null || { - print_error "Failed to copy OVMF_VARS.fd!" - print_info "Trying to install OVMF firmware..." - - # Try to install OVMF - if command -v apt-get >/dev/null 2>&1; then - sudo apt-get update && sudo apt-get install -y ovmf - elif command -v yum >/dev/null 2>&1; then - sudo yum install -y edk2-ovmf - elif command -v pacman >/dev/null 2>&1; then - sudo pacman -S --noconfirm edk2-ovmf - fi - - # Try to locate again after installation - locate_ovmf - return - } - fi - - # Check if required files exist - if [[ -z "$OVMF_CODE" || ! -f "$OVMF_CODE" ]]; then - print_error "OVMF_CODE.fd not found!" - print_info "Please install OVMF firmware package:" - print_info " Ubuntu/Debian: sudo apt install ovmf" - print_info " RHEL/CentOS: sudo yum install edk2-ovmf" - print_info " Arch: sudo pacman -S edk2-ovmf" - exit 1 - fi - if [[ ! -f "$OVMF_VARS" ]]; then - print_error "OVMF_VARS.fd not found or could not be copied!" - exit 1 - fi - - print_success "Found OVMF firmware: $OVMF_CODE" - print_success "Using OVMF vars: $OVMF_VARS" -} - -# Create VM disk image -create_disk() { - # Check if the qcow2 image file exists; if not, create it - if [[ ! -f "$QCOW2_FILE" ]]; then - print_info "Creating $QCOW2_FILE with a size of $VM_SIZE" - qemu-img create -f qcow2 "$QCOW2_FILE" "$VM_SIZE" || { - print_error "Failed to create qcow2 image!" - exit 1 - } - print_success "Created VM disk image: $QCOW2_FILE" - else - print_success "VM disk image already exists: $QCOW2_FILE" - fi -} - -# Helper function to convert QCOW2 to RAW for stealth -convert_to_raw() { - if [[ -f "$QCOW2_FILE" && ! -f "$RAW_FILE" ]]; then - print_info "Converting QCOW2 to RAW format for stealth..." - qemu-img convert -f qcow2 -O raw "$QCOW2_FILE" "$RAW_FILE" || { - print_error "Failed to convert to RAW format" - exit 1 - } - print_success "Successfully converted to RAW format: $RAW_FILE" - elif [[ ! -f "$RAW_FILE" ]]; then - print_info "Creating RAW disk image..." - qemu-img create -f raw "$RAW_FILE" "$VM_SIZE" || { - print_error "Failed to create RAW disk image" - exit 1 - } - print_success "Created RAW disk image: $RAW_FILE" - else - print_success "RAW disk image already exists: $RAW_FILE" - fi -} - -# Check dependencies -check_dependencies() { - local missing_deps=() - - # Check for essential tools - command -v qemu-system-x86_64 >/dev/null 2>&1 || missing_deps+=("qemu-system-x86_64") - command -v swtpm >/dev/null 2>&1 || missing_deps+=("swtpm") - command -v curl >/dev/null 2>&1 || missing_deps+=("curl") - command -v uuidgen >/dev/null 2>&1 || missing_deps+=("uuidgen") - command -v openssl >/dev/null 2>&1 || missing_deps+=("openssl") - - if [[ ${#missing_deps[@]} -gt 0 ]]; then - print_error "Missing required dependencies: ${missing_deps[*]}" - print_info "Please install them using your package manager:" - print_info " Ubuntu/Debian: sudo apt install qemu-system-x86 swtpm curl uuid-runtime openssl" - print_info " RHEL/CentOS: sudo yum install qemu-kvm swtpm curl util-linux openssl" - print_info " Arch: sudo pacman -S qemu swtpm curl util-linux openssl" - exit 1 - fi -} - -start_vm() { - # Verify that we have a Windows ISO - if [[ -z "$WINDOWS_ISO_PATH" || ! -f "$WINDOWS_ISO_PATH" ]]; then - print_error "Windows ISO file not found. Cannot start VM." - print_info "Please download Windows 11 ISO and save it to: $WIN_ISO_DIR" - exit 1 - fi - - # Anti-detection: Generate realistic hardware identifiers - REAL_MAC="00:1A:79:$(openssl rand -hex 3 | sed 's/../&:/g; s/:$//')" # Dell OUI - REAL_SERIAL="$(openssl rand -hex 8 | tr '[:lower:]' '[:upper:]')" - REAL_UUID="$(uuidgen)" - REAL_VENDOR="Dell Inc." - REAL_PRODUCT="OptiPlex 7090" - REAL_VERSION="01" - REAL_FAMILY="OptiPlex" - - # Stop any existing swtpm process for this VM - if [[ -f "$TPM_SOCKET" ]]; then - print_info "Cleaning up existing TPM socket..." - rm -f "$TPM_SOCKET" - fi - - # Start swtpm (TPM emulator) - print_info "Starting TPM emulator..." - /sbin/swtpm socket \ - --ctrl type=unixio,path="$TPM_SOCKET" \ - --terminate \ - --tpmstate dir="$TPM_DIR" \ - --tpm2 & - - # Give swtpm a moment to create the socket - sleep 1 - - # Verify TPM socket exists - if [[ ! -S "$TPM_SOCKET" ]]; then - print_error "TPM socket not created: $TPM_SOCKET" - exit 1 - fi - - print_info "Starting stealth Windows 11 VM..." - print_info "Using Windows ISO: $WINDOWS_ISO_PATH" - print_info "VM will boot from unattended installation ISO" - print_info "Default login: Username=User, Password=password" - print_info "Anti-detection measures enabled" - - # Build qemu arguments in an array for safety and readability - QEMU_ARGS=( - # Basic VM configuration - -name "$REAL_PRODUCT",process="$VM_NAME" - -machine q35,hpet=off,smm=on,vmport=off,accel=kvm - - # Global optimizations - -global kvm-pit.lost_tick_policy=discard - -global ICH9-LPC.disable_s3=1 - - # CPU configuration (stealth) - -cpu host,-hypervisor,+invtsc,+ssse3,l3-cache=on,migratable=no - -smp "$SMP_CONFIG" - -m "$VM_RAM" - - # SMBIOS spoofing for anti-detection - -smbios type=0,vendor="$REAL_VENDOR",version="$REAL_VERSION",date="03/15/2023" - -smbios type=1,manufacturer="$REAL_VENDOR",product="$REAL_PRODUCT",version="$REAL_VERSION",serial="$REAL_SERIAL",uuid="$REAL_UUID",family="$REAL_FAMILY" - -smbios type=2,manufacturer="$REAL_VENDOR",product="0NK70N",version="A00",serial="$REAL_SERIAL" - -smbios type=3,manufacturer="$REAL_VENDOR",version="$REAL_VERSION",serial="$REAL_SERIAL" - -smbios type=4,manufacturer="Intel(R) Corporation",version="11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz" - - # Process management - -pidfile "$VM_DIR/$VM_NAME.pid" - -rtc base=localtime,clock=host,driftfix=slew - - # Display and graphics - -vga qxl - -display sdl - - # Boot configuration - -boot menu=on,splash-time=0,order=d,reboot-timeout=5000 - - # Random number generator - -object rng-random,id=rng0,filename=/dev/urandom - -device i82801b11-bridge,id=pci.1 - - # usb - -device usb-ehci,id=usb - -device usb-kbd,bus=usb.0 - -device usb-tablet,bus=usb.0 - -k en-us - - # audio (pipewire) - -audiodev pipewire,id=audio0 - -device AC97,audiodev=audio0 - - # Network (realistic NIC with stealth MAC) - -device rtl8139,netdev=nic,mac="$REAL_MAC" - -netdev user,hostname="$VM_NAME",hostfwd=tcp::"$HOST_PORT"-:"$GUEST_PORT",smb="$SHARED_DIR",id=nic - - # UEFI firmware - -global driver=cfi.pflash01,property=secure,value=on - -drive if=pflash,format=raw,unit=0,file="$OVMF_CODE",readonly=on - -drive if=pflash,format=raw,unit=1,file="$OVMF_VARS" - - # Main storage (AHCI for compatibility) - -device ahci,id=ahci - -drive if=none,id=disk0,format=raw,file="$RAW_FILE",cache=writeback - -device ide-hd,bus=ahci.0,drive=disk0 - - # CD-ROM drives (Windows ISO + Unattended) - -drive media=cdrom,index=0,file="$WINDOWS_ISO_PATH",if=ide - -drive media=cdrom,index=1,file="$ISO_UNATTENDED",if=ide - - # TPM 2.0 - -chardev socket,id=chrtpm,path="$TPM_SOCKET" - -tpmdev emulator,id=tpm0,chardev=chrtpm - -device tpm-tis,tpmdev=tpm0 - - # Monitoring and management sockets - -monitor unix:"$SOCKET_DIR/$VM_NAME-monitor.socket",server,nowait - -serial unix:"$SOCKET_DIR/$VM_NAME-serial.socket",server,nowait - ) - - # Add VirtIO ISO if it exists (as fallback) - if [[ -f "$ISO_VIRTIO" ]]; then - QEMU_ARGS+=(-drive media=cdrom,index=2,file="$ISO_VIRTIO",if=ide,readonly=on) - fi - - print_info "Starting QEMU with stealth configuration..." - print_info "Monitor socket: $SOCKET_DIR/$VM_NAME-monitor.socket" - print_info "Serial socket: $SOCKET_DIR/$VM_NAME-serial.socket" - print_info "SSH port forwarding: localhost:$HOST_PORT -> VM:$GUEST_PORT" - - # Execute qemu - exec qemu-system-x86_64 "${QEMU_ARGS[@]}" - -} - -# Helper function to convert QCOW2 to RAW for stealth -convert_to_raw() { - if [[ -f "$QCOW2_FILE" && ! -f "$RAW_FILE" ]]; then - print_info "Converting QCOW2 to RAW format for stealth..." - qemu-img convert -f qcow2 -O raw "$QCOW2_FILE" "$RAW_FILE" - if [[ $? -eq 0 ]]; then - print_success "Successfully converted to RAW format" - else - print_error "Failed to convert to RAW format" - exit 1 - fi - elif [[ ! -f "$RAW_FILE" ]]; then - print_info "Creating RAW disk image..." - qemu-img create -f raw "$RAW_FILE" "$VM_SIZE" - fi -} - -# Anti-detection validation commands -show_validation_commands() { - cat << 'EOF' -=== VM DETECTION VALIDATION COMMANDS === - -Run these commands inside Windows to verify stealth: - -# PowerShell - Check hardware info: -Get-WmiObject -Class Win32_ComputerSystem | Select-Object Manufacturer, Model, TotalPhysicalMemory -Get-WmiObject -Class Win32_BIOS | Select-Object Manufacturer, Version, SerialNumber -Get-WmiObject -Class Win32_BaseBoard | Select-Object Manufacturer, Product, SerialNumber -Get-WmiObject -Class Win32_Processor | Select-Object Name, Manufacturer, MaxClockSpeed - -# Check for hypervisor presence: -Get-WmiObject -Class Win32_ComputerSystem | Select-Object HypervisorPresent -bcdedit /enum | findstr hypervisorlaunchtype - -# Registry checks for VM artifacts: -reg query "HKLM\HARDWARE\DESCRIPTION\System" /v SystemBiosVersion -reg query "HKLM\HARDWARE\DESCRIPTION\System\BIOS" /v SystemManufacturer -reg query "HKLM\SYSTEM\CurrentControlSet\Services" | findstr -i "vbox\|vmware\|qemu\|virtio" - -# Check network adapter: -Get-WmiObject -Class Win32_NetworkAdapter | Where-Object {$_.NetConnectionStatus -eq 2} | Select-Object Name, MACAddress, Manufacturer - -# Check PCI devices for VM signatures: -Get-WmiObject -Class Win32_PnPEntity | Where-Object {$_.Name -match "VirtIO|QEMU|VMware|VirtualBox|Hyper-V"} | Select-Object Name, DeviceID - -# Check running services: -Get-Service | Where-Object {$_.Name -match "vbox|vmware|qemu|virtio|spice"} - -# Check for VM-specific processes: -Get-Process | Where-Object {$_.ProcessName -match "vbox|vmware|qemu|virtio"} - -# Additional checks: -systeminfo | findstr /C:"System Manufacturer" /C:"System Model" /C:"BIOS Version" -wmic computersystem get manufacturer,model,name,systemtype - -EOF -} - -# Cleanup function -cleanup() { - print_info "Cleaning up..." - - # Kill swtpm if running - if [[ -f "$TPM_SOCKET" ]]; then - pkill -f "swtpm.*$TPM_SOCKET" 2>/dev/null || true - rm -f "$TPM_SOCKET" 2>/dev/null || true - fi - - # Remove PID file - if [[ -f "$VM_DIR/$VM_NAME.pid" ]]; then - rm -f "$VM_DIR/$VM_NAME.pid" 2>/dev/null || true - fi -} - -# Trap cleanup on exit -trap cleanup EXIT - -# Main execution function -main() { - print_info "=== Windows 11 Stealth VM Setup ===" - print_info "VM Name: $VM_NAME" - print_info "VM Size: $VM_SIZE" - print_info "VM RAM: $VM_RAM" - print_info "VM CPUs: $VM_CPU" - print_info "Host Port: $HOST_PORT" - - check_dependencies - prepare_files - locate_ovmf - create_disk - convert_to_raw - show_validation_commands - - print_success "Setup complete! Starting VM..." - start_vm -} - -# Run main function -main "$@" diff --git a/unix/virt/server.sh b/unix/virt/server.sh deleted file mode 100755 index 6d937fd..0000000 --- a/unix/virt/server.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env bash - -# Set variables -HOST_DIR="machines" -VM_NAME="proxmox" -VM_DIR="$HOME/machines/vm" -IMAGE_DIR="$HOME/machines/images" -SOCKET_DIR="$VM_DIR" -#ISO_FILE="$IMAGE_DIR/proxmox-ve_8.3-1.iso" -ISO_FILE=$(find "$IMAGE_DIR" -type f -iname "proxmox*.iso" -exec stat --format="%Y %n" {} \; | sort -n | tail -n 1 | cut -d' ' -f2-) -QCOW2_FILE="$VM_DIR/$VM_NAME.qcow2" -HOST_PORT=22220 -GUEST_PORT=22 -SHARED_DIR="$HOME/machines/shared" -FIRMWARE_DIR="$HOME/machines/firmware" -VM_SIZE="300G" # Disk size in GB -VM_RAM="12G" # RAM size -VM_CPU="6" # Number of virtual CPUs -CORES=$((VM_CPU / 2)) -THREADS_PER_CORE=2 -SOCKETS=1 - -# Set SMP configuration -SMP_CONFIG="cores=$CORES,threads=$THREADS_PER_CORE,sockets=$SOCKETS" - -# Ensure necessary directories exist -mkdir -p "$HOME"/"$HOST_DIR" -mkdir -p "$VM_DIR" "$IMAGE_DIR" "$SHARED_DIR" "$FIRMWARE_DIR" - -# Locate OVMF firmware files -OVMF_DIRS=( - "/usr/share/OVMF" - "/usr/share/qemu" - "/usr/lib/qemu" - "/usr/share/edk2" - "/usr/lib/edk2" -) - -OVMF_CODE="" -OVMF_VARS="" - -for dir in "${OVMF_DIRS[@]}"; do - [[ -z "$OVMF_CODE" ]] && OVMF_CODE=$(find "$dir" -type f -name "OVMF_CODE.fd" -o -name "edk2-x86_64-code.fd" 2>/dev/null | head -n 1) - [[ -z "$OVMF_VARS" ]] && OVMF_VARS=$(find "$dir" -type f -name "OVMF_VARS.fd" 2>/dev/null | head -n 1) - [[ -n "$OVMF_CODE" && -n "$OVMF_VARS" ]] && break -done - -# Ensure a writable copy of OVMF_VARS.fd -OVMF_VARS="$FIRMWARE_DIR/OVMF_VARS.fd" - -if [[ ! -f "$OVMF_VARS" ]]; then - echo "Copying OVMF_VARS.fd to $OVMF_VARS" - cp /usr/share/edk2/OvmfX64/OVMF_VARS.fd "$OVMF_VARS" 2>/dev/null || { - echo "Error: Failed to copy OVMF_VARS.fd!" >&2 - exit 1 - } -fi - -# Check if required files exist -if [[ -z "$OVMF_CODE" ]]; then - echo "Error: OVMF_CODE.fd not found!" >&2 - exit 1 -fi -if [[ ! -f "$OVMF_VARS" ]]; then - echo "Error: OVMF_VARS.fd not found or could not be copied!" >&2 - exit 1 -fi -if [[ ! -f "$ISO_FILE" ]]; then - echo "Warning: $ISO_FILE ISO not found at $IMAGE_DIR" -fi - -# Check if the qcow2 image file exists; if not, create it -if [[ ! -f "$QCOW2_FILE" ]]; then - echo "Creating $QCOW2_FILE with a size of $VM_SIZE" - qemu-img create -f qcow2 "$QCOW2_FILE" "$VM_SIZE" || { - echo "Error: Failed to create qcow2 image!" >&2 - exit 1 - } -else - echo "" -fi - -# Run QEMU -/sbin/qemu-system-x86_64 \ - -name "$VM_NAME",process="$VM_NAME" \ - -machine q35,smm=off,vmport=off,accel=kvm \ - -global kvm-pit.lost_tick_policy=discard \ - -cpu host \ - -smp "$SMP_CONFIG" \ - -m "$VM_RAM" \ - -device virtio-balloon \ - -pidfile "$VM_DIR/$VM_NAME.pid" \ - -rtc base=utc,clock=host \ - -vga none \ - -device virtio-vga-gl,xres=1280,yres=800 \ - -display sdl,gl=on \ - -device virtio-rng-pci,rng=rng0 \ - -object rng-random,id=rng0,filename=/dev/urandom \ - -device qemu-xhci,id=spicepass \ - -chardev spicevmc,id=usbredirchardev1,name=usbredir \ - -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \ - -chardev spicevmc,id=usbredirchardev2,name=usbredir \ - -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2 \ - -chardev spicevmc,id=usbredirchardev3,name=usbredir \ - -device usb-redir,chardev=usbredirchardev3,id=usbredirdev3 \ - -device pci-ohci,id=smartpass \ - -device usb-ccid \ - -device usb-ehci,id=input \ - -device usb-kbd,bus=input.0 \ - -k en-us \ - -device usb-tablet,bus=input.0 \ - -audiodev pipewire,id=audio0 \ - -device intel-hda \ - -device hda-micro,audiodev=audio0 \ - -device virtio-net,netdev=nic \ - -netdev user,hostname="$VM_NAME",hostfwd=tcp::"$HOST_PORT"-:"$GUEST_PORT",id=nic \ - -fsdev local,id=fsdev0,path="$SHARED_DIR",security_model=mapped-xattr \ - -device virtio-9p-pci,fsdev=fsdev0,mount_tag="SharedDir" \ - -global driver=cfi.pflash01,property=secure,value=on \ - -drive if=pflash,format=raw,unit=0,file="$OVMF_CODE",readonly=on \ - -drive if=pflash,format=raw,unit=1,file="$OVMF_VARS" \ - -drive media=cdrom,index=0,file="$ISO_FILE" \ - -device virtio-blk-pci,drive=SystemDisk \ - -drive id=SystemDisk,if=none,format=qcow2,file="$QCOW2_FILE" \ - -monitor unix:"$SOCKET_DIR/$VM_NAME-monitor.socket",server,nowait \ - -serial unix:"$SOCKET_DIR/$VM_NAME-serial.socket",server,nowait -#-serial unix:"$SOCKET_DIR/$VM_NAME-serial.socket",server,nowait 2>/dev/null -#-netdev user,hostname="$VM_NAME",hostfwd=tcp::"$HOST_PORT"-:"$GUEST_PORT",smb="$SHARED_DIR",id=nic \ diff --git a/unix/virt/ubuntu b/unix/virt/ubuntu deleted file mode 100755 index c93941d..0000000 --- a/unix/virt/ubuntu +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/env bash - -# Set variables -HOST_DIR="$HOME/virt" -VM_DIR="$HOME/virt/machines" -IMAGE_DIR="$HOME/virt/images" -SOCKET_DIR="$VM_DIR" - -BASE_NAME=$(basename "$0" .sh | sed 's/[0-9]*$//') -VM_INDEX=$(basename "$0" .sh | grep -o '[0-9]*$') -VM_INDEX=${VM_INDEX:-1} # default to 1 if no number - -VM_NAME="${BASE_NAME}${VM_INDEX}" -QCOW2_FILE="$VM_DIR/$VM_NAME.qcow2" - -# If the file exists, use it -if [[ -f "$QCOW2_FILE" ]]; then - echo "Using existing VM image: $QCOW2_FILE" -else - # Loop to find first available index if not - while [[ -f "$QCOW2_FILE" ]]; do - ((VM_INDEX++)) - VM_NAME="${BASE_NAME}${VM_INDEX}" - QCOW2_FILE="$VM_DIR/$VM_NAME.qcow2" - done - echo "Creating new VM image: $QCOW2_FILE" - qemu-img create -f qcow2 "$QCOW2_FILE" "$VM_SIZE" || { - echo "Error: Failed to create qcow2 image!" >&2 - exit 1 - } -fi - -#ISO_FILE=$(ls -1t "$IMAGE_DIR"/ubuntu-*-desktop-*-amd64.iso 2>/dev/null | head -n1) -#if [[ -z "$ISO_FILE" ]]; then -# echo "Error: No Ubuntu ISO found in $IMAGE_DIR" >&2 -# exit 1 -#fi -#echo "Using ISO: $ISO_FILE" - -# Directory to remember ISO choices -CHOICES_DIR="$VM_DIR/.iso_choices" -mkdir -p "$CHOICES_DIR" - -CHOICE_FILE="$CHOICES_DIR/$BASE_NAME.choice" - -if [[ -f "$CHOICE_FILE" ]]; then - # Already have a saved ISO for this VM - ISO_FILE=$(<"$CHOICE_FILE") - echo "Using previously selected ISO: $ISO_FILE" -else - # List all ISO files newest first - mapfile -t ISO_LIST < <(ls -1t "$IMAGE_DIR"/*.iso 2>/dev/null) - if [[ ${#ISO_LIST[@]} -eq 0 ]]; then - echo "Error: No ISO files found in $IMAGE_DIR" >&2 - exit 1 - fi - - echo "Available ISOs:" - PS3="Select an ISO to boot (default: 1): " - select ISO_FILE in "${ISO_LIST[@]}"; do - ISO_FILE=${ISO_FILE:-${ISO_LIST[0]}} - echo "Using ISO: $ISO_FILE" - # Save choice so we donât ask again - echo "$ISO_FILE" > "$CHOICE_FILE" - break - done -fi - -QCOW2_FILE="$VM_DIR/$VM_NAME.qcow2" -GUEST_PORT=22 -SHARED_DIR="$HOST_DIR/shared" -VM_SIZE="60G" # Disk size in GB -VM_RAM="8G" # RAM size -VM_CPU="6" # Number of virtual CPUs -CORES=$((VM_CPU / 2)) -THREADS_PER_CORE=2 -SOCKETS=1 -SHARED_DIR="$HOST_DIR/shared" -FIRMWARE_DIR="$HOST_DIR/firmware" - -SMP_CONFIG="cores=$CORES,threads=$THREADS_PER_CORE,sockets=$SOCKETS" - -# Set SPICE_NOGRAB environment variable -export SPICE_NOGRAB=1 - -# Try to find an available host port starting from 22220 -HOST_PORT_START=22220 -HOST_PORT_END=22300 - -for ((port = HOST_PORT_START; port <= HOST_PORT_END; port++)); do - if ! ss -tuln | grep -q ":$port\b"; then - HOST_PORT=$port - echo "Using available port: $HOST_PORT" - break - fi -done - -if [[ $port -gt $HOST_PORT_END ]]; then - echo "Error: No available ports found between $HOST_PORT_START and $HOST_PORT_END" >&2 - exit 1 -fi - -# Ensure necessary directories exist -mkdir -p "$HOST_DIR" -mkdir -p "$VM_DIR" "$IMAGE_DIR" "$SHARED_DIR" "$FIRMWARE_DIR" - -# Locate OVMF firmware files -OVMF_DIRS=( - "/usr/share/OVMF" - "/usr/share/qemu" - "/usr/lib/qemu" - "/usr/share/edk2" - "/usr/lib/edk2" -) - -OVMF_CODE="" -OVMF_VARS="" - -for dir in "${OVMF_DIRS[@]}"; do - [[ -z "$OVMF_CODE" ]] && OVMF_CODE=$(find "$dir" -type f -name "OVMF_CODE.fd" -o -name "edk2-x86_64-code.fd" 2>/dev/null | head -n 1) - [[ -z "$OVMF_VARS" ]] && OVMF_VARS=$(find "$dir" -type f -name "OVMF_VARS.fd" 2>/dev/null | head -n 1) - [[ -n "$OVMF_CODE" && -n "$OVMF_VARS" ]] && break -done - -# Ensure a writable copy of OVMF_VARS.fd -OVMF_VARS="$IMAGE_DIR/OVMF_VARS.fd" - -if [[ ! -f "$OVMF_VARS" ]]; then - echo "Copying OVMF_VARS.fd to $OVMF_VARS" - cp /usr/share/edk2/OvmfX64/OVMF_VARS.fd "$OVMF_VARS" 2>/dev/null || { - echo "Error: Failed to copy OVMF_VARS.fd!" >&2 - exit 1 - } -fi - -# Check if required files exist -if [[ -z "$OVMF_CODE" ]]; then - echo "Error: OVMF_CODE.fd not found!" >&2 - exit 1 -fi -if [[ ! -f "$OVMF_VARS" ]]; then - echo "Error: OVMF_VARS.fd not found or could not be copied!" >&2 - exit 1 -fi -if [[ ! -f "$ISO_FILE" ]]; then - echo "Warning: $ISO_FILE ISO not found at $IMAGE_DIR" -fi - -# Check if the qcow2 image file exists; if not, create it -if [[ ! -f "$QCOW2_FILE" ]]; then - echo "Creating $QCOW2_FILE with a size of $VM_SIZE" - qemu-img create -f qcow2 "$QCOW2_FILE" "$VM_SIZE" || { - echo "Error: Failed to create qcow2 image!" >&2 - exit 1 - } -else - echo "" -fi - -# Run QEMU -/sbin/qemu-system-x86_64 \ - -name "$VM_NAME",process="$VM_NAME" \ - -machine q35,smm=off,vmport=off,accel=kvm \ - -enable-kvm \ - -global kvm-pit.lost_tick_policy=discard \ - -cpu host \ - -smp "$SMP_CONFIG" \ - -m "$VM_RAM" \ - -device virtio-balloon \ - -pidfile "$VM_DIR/$VM_NAME.pid" \ - -rtc base=utc,clock=host \ - -vga none \ - -device virtio-vga-gl,xres=1280,yres=800 \ - -display sdl,gl=on \ - -device virtio-rng-pci,rng=rng0 \ - -device virtio-serial \ - -object rng-random,id=rng0,filename=/dev/urandom \ - -device qemu-xhci,id=spicepass \ - -chardev spicevmc,id=usbredirchardev1,name=usbredir \ - -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \ - -chardev spicevmc,id=usbredirchardev2,name=usbredir \ - -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2 \ - -chardev spicevmc,id=usbredirchardev3,name=usbredir \ - -device usb-redir,chardev=usbredirchardev3,id=usbredirdev3 \ - -device pci-ohci,id=smartpass \ - -device usb-ccid \ - -device usb-ehci,id=input \ - -device usb-kbd,bus=input.0 \ - -k en-us \ - -device usb-tablet,bus=input.0 \ - -audiodev pipewire,id=audio0 \ - -device intel-hda \ - -device hda-micro,audiodev=audio0 \ - -device virtio-net,netdev=nic \ - -netdev user,hostname="$VM_NAME",hostfwd=tcp::"$HOST_PORT"-:"$GUEST_PORT",id=nic \ - -device virtio-9p-pci,fsdev=fsdev0,mount_tag="Public-$(whoami)" \ - -global driver=cfi.pflash01,property=secure,value=on \ - -drive if=pflash,format=raw,unit=0,file="$OVMF_CODE",readonly=on \ - -drive if=pflash,format=raw,unit=1,file="$OVMF_VARS" \ - -drive media=cdrom,index=0,file="$ISO_FILE" \ - -device virtio-blk-pci,drive=SystemDisk \ - -drive id=SystemDisk,if=none,format=qcow2,file="$QCOW2_FILE" \ - -fsdev local,id=fsdev0,path="$SHARED_DIR",security_model=mapped-xattr \ - -monitor unix:"$SOCKET_DIR/$VM_NAME-monitor.socket",server,nowait \ - -serial unix:"$SOCKET_DIR/$VM_NAME-serial.socket",server,nowait - -#-display sdl,gl=on \ -#-display gtk,gl=on \ -#-display gtk,grab-on-hover=on,grab-mod=none \ -#-qmp unix:/tmp/qmp-sock,server,nowait \ -#-qmp unix:"$SOCKET_DIR/$VM_NAME-qmp.socket",server,nowait \ -#-chardev socket,path="$VM_DIR/$VM_NAME-qga.sock",server=on,wait=off,id=qga0 \ - -# Network Isolation: -#-netdev user,hostname="$VM_NAME",restrict=yes,id=nic \ - -# No file-sharing: -#-netdev user,hostname="$VM_NAME",hostfwd=tcp::"$HOST_PORT"-:"$GUEST_PORT",id=nic \ - -# File-sharing and networking: -#-netdev user,hostname="$VM_NAME",hostfwd=tcp::"$HOST_PORT"-:"$GUEST_PORT",smb="$SHARED_DIR",id=nic \ -#-device virtio-9p-pci,fsdev=fsdev0,mount_tag="Public-$(whoami)" \ diff --git a/unix/virt/windows.sh b/unix/virt/windows.sh deleted file mode 100755 index 1863f8a..0000000 --- a/unix/virt/windows.sh +++ /dev/null @@ -1,1156 +0,0 @@ -#!/usr/bin/env bash - -# Windows VM Creation Script -# Description: Creates and manages Windows virtual machines using QEMU/KVM -# Features: -# - Supports Windows 10, 11, and Server -# - Automatic dependency checking -# - Multiple VM instance support -# - Cache management -# - Unattended installation -# - SMB sharing support -# - Network control - -# Usage: ./windows.sh [VERSION] [OPTIONS] -# Versions: -# 10 Windows 10 -# 11 Windows 11 (default) -# server Windows Server 2022 -# server2019 Windows Server 2019 -# server2016 Windows Server 2016 - -# Options: -# --help Show this help message -# --clean Clean dependency cache -# --check-deps Only check dependencies and exit -# --download-iso Download Windows ISO and exit -# --name NAME Set custom VM name -# --ram SIZE Set RAM size (default: 8G) -# --cpu NUM Set number of CPUs (default: 6) -# --disk SIZE Set disk size (default: 80G) -# --enable-smb Enable SMB sharing (default: disabled) -# --disable-net Disable network connectivity (default: enabled) - -# Parse command line arguments -WINDOWS_VERSION="11" -CLEAN_CACHE=false -CHECK_DEPS_ONLY=false -DOWNLOAD_ISO_ONLY=false -VM_NAME="windows-11" -VM_RAM="8G" -VM_CPU="6" -VM_SIZE="80G" -ENABLE_SMB=false -DISABLE_NET=false - -# Handle version argument if it's the first argument -if [[ $# -gt 0 && ! $1 =~ ^-- ]]; then - case "$1" in - "10") - WINDOWS_VERSION="10" - VM_NAME="windows-10" - ;; - "server" | "server2022") - WINDOWS_VERSION="server2022" - VM_NAME="windows-server-2022" - ;; - "server2019") - WINDOWS_VERSION="server2019" - VM_NAME="windows-server-2019" - ;; - "server2016") - WINDOWS_VERSION="server2016" - VM_NAME="windows-server-2016" - ;; - *) - echo "Unknown Windows version: $1" - echo "Use --help for usage information" - exit 1 - ;; - esac - shift -fi - -while [[ $# -gt 0 ]]; do - case $1 in - --help) - echo "Windows VM Creation Script" - echo "Usage: $0 [VERSION] [OPTIONS]" - echo - echo "Versions:" - echo " 10 Windows 10" - echo " 11 Windows 11 (default)" - echo " server Windows Server 2022" - echo " server2019 Windows Server 2019" - echo " server2016 Windows Server 2016" - echo - echo "Options:" - echo " --help Show this help message" - echo " --clean Clean dependency cache" - echo " --check-deps Only check dependencies and exit" - echo " --download-iso Download Windows ISO and exit" - echo " --name NAME Set custom VM name" - echo " --ram SIZE Set RAM size (default: 8G)" - echo " --cpu NUM Set number of CPUs (default: 6)" - echo " --disk SIZE Set disk size (default: 80G)" - echo " --enable-smb Enable SMB sharing (default: disabled)" - echo " --disable-net Disable network connectivity (default: enabled)" - exit 0 - ;; - --clean) - CLEAN_CACHE=true - shift - ;; - --check-deps) - CHECK_DEPS_ONLY=true - shift - ;; - --download-iso) - DOWNLOAD_ISO_ONLY=true - shift - ;; - --name) - VM_NAME="$2" - shift 2 - ;; - --ram) - VM_RAM="$2" - shift 2 - ;; - --cpu) - VM_CPU="$2" - shift 2 - ;; - --disk) - VM_SIZE="$2" - shift 2 - ;; - --enable-smb) - ENABLE_SMB=true - shift - ;; - --disable-net) - DISABLE_NET=true - shift - ;; - *) - echo "Unknown option: $1" - echo "Use --help for usage information" - exit 1 - ;; - esac -done - -# Set variables -HOST_DIR="$HOME/virt-new-new" -VM_DIR="$HOST_DIR/machines" -IMAGE_DIR="$HOST_DIR/images" -WIN_ISO_DIR="${IMAGE_DIR}/${VM_NAME}" # Directory for Windows ISO -SOCKET_DIR="$VM_DIR" -SHARED_DIR="${HOST_DIR}/shared" -FIRMWARE_DIR="${HOST_DIR}/firmware" -TPM_DIR="$WIN_ISO_DIR" -TPM_SOCKET="${WIN_ISO_DIR}/${VM_NAME}.swtpm-sock" -GUEST_PORT=22 -QCOW2_FILE="${VM_DIR}/${VM_NAME}.qcow2" - -# Try to find an available host port starting from 22220 -HOST_PORT_START=22220 -HOST_PORT_END=22300 - -for ((port = HOST_PORT_START; port <= HOST_PORT_END; port++)); do - if ! ss -tuln | grep -q ":$port\b"; then - HOST_PORT=$port - echo "Using available port: $HOST_PORT" - break - fi -done - -if [[ $port -gt $HOST_PORT_END ]]; then - echo "Error: No available ports found between $HOST_PORT_START and $HOST_PORT_END" >&2 - exit 1 -fi - -# Set SMP configuration -CORES=$((VM_CPU / 2)) -THREADS_PER_CORE=2 -SOCKETS=1 -SMP_CONFIG="cores=$CORES,threads=$THREADS_PER_CORE,sockets=$SOCKETS" - -# Create necessary directories -mkdir -p "${HOME}/${HOST_DIR}" -mkdir -p "$IMAGE_DIR" "$SHARED_DIR" "$FIRMWARE_DIR" -mkdir -p "$WIN_ISO_DIR" "$VM_DIR" -mkdir -p "${WIN_ISO_DIR}/unattended" - -# Define ISO paths and URLs -ISO_VIRTIO="${WIN_ISO_DIR}/virtio-win.iso" -ISO_UNATTENDED="${WIN_ISO_DIR}/unattended.iso" - -# Find Windows ISO with flexible pattern matching -find_windows_iso() { - # Check if directory exists - if [[ ! -d "$WIN_ISO_DIR" ]]; then - mkdir -p "$WIN_ISO_DIR" - fi - - # Try to find any Windows ISO using case-insensitive patterns - local found_iso - found_iso=$(find "$WIN_ISO_DIR" -maxdepth 1 -type f \( \ - -iname "*win11*.iso" -o \ - -iname "*win*11*.iso" -o \ - -iname "Win*.iso" -o \ - -iname "Win11*.iso" -o \ - -iname "Win*11*.iso" -o \ - -iname "*windows*11*.iso" -o \ - -iname "*windows11*.iso" \ - \) -exec stat --format="%Y %n" {} \; | sort -n | tail -n 1 | cut -d' ' -f2-) - - if [[ -n "$found_iso" && -f "$found_iso" ]]; then - echo "$found_iso" - return 0 - fi - - return 1 -} - -# Define download URLs -VIRTIO_ISO_URL="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" -SPICE_WEBDAVD_URL="https://www.spice-space.org/download/windows/spice-webdavd/spice-webdavd-x64-latest.msi" -SPICE_VDAGENT_URL="https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-latest.msi" -SPICE_VDAGENT_FALLBACK_URL="https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-0.10.0.msi" -USBDK_URL="https://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.22_x64.msi" - -# Fido download URL (Windows ISO downloader) -#FIDO_URL="https://github.com/pbatard/Fido/raw/master/Fido.ps1" -#FIDO_PATH="$WIN_DIR/Fido.ps1" - -# Print colored messages -print_info() { echo -e "\033[1;34m[INFO]\033[0m $1" >&2; } -print_success() { echo -e "\033[1;32m[SUCCESS]\033[0m $1" >&2; } -print_warning() { echo -e "\033[1;33m[WARNING]\033[0m $1" >&2; } -print_error() { echo -e "\033[1;31m[ERROR]\033[0m $1" >&2; } - -# Helper: verify file integrity -verify_file() { - local file="$1" - local expected_sha256="$2" - - if [[ ! -f "$file" ]]; then - return 1 - fi - - if [[ -n "$expected_sha256" ]]; then - local actual_sha256 - actual_sha256=$(sha256sum "$file" | cut -d' ' -f1) - if [[ "$actual_sha256" != "$expected_sha256" ]]; then - print_error "File integrity check failed for $file" - return 1 - fi - fi - - return 0 -} - -# Helper: download file with verification -download_file() { - local url="$1" - local dest="$2" - local expected_sha256="$3" - local allow_failure="$4" - - # Check if file exists and is valid - if [[ -f "$dest" ]]; then - if verify_file "$dest" "$expected_sha256"; then - print_info "File $dest already exists and verified." - return 0 - else - print_warning "File $dest exists but failed verification. Redownloading..." - rm -f "$dest" - fi - fi - - print_info "Downloading $url..." - if ! curl -fL --progress-bar -o "$dest" "$url"; then - print_error "Failed to download $url." - if [[ "$allow_failure" != "true" ]]; then - return 1 - fi - else - # Verify downloaded file - if ! verify_file "$dest" "$expected_sha256"; then - print_error "Downloaded file failed verification" - rm -f "$dest" - return 1 - fi - print_success "Successfully downloaded and verified $dest" - fi - - return 0 -} - -# Download Windows 11 ISO using Microsoft's API -download_windows_iso() { - local windows_version="11" # Default to Windows 11 - local language="English (United States)" # Default language - - # Parse arguments if provided - if [[ -n "$1" ]]; then - windows_version="$1" - fi - - print_info "Attempting to download Windows $windows_version ISO from Microsoft..." - - # Set required variables - local user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0" - local session_id="$(uuidgen)" - local profile="606624d44113" - local url="https://www.microsoft.com/en-us/software-download/windows$windows_version" - - # Add ISO to URL for Windows 10 - case "$windows_version" in - 10) url="${url}ISO" ;; - esac - - # Step 1: Get download page HTML - print_info "Fetching download page: $url" - local iso_download_page_html - iso_download_page_html="$(curl --disable --silent --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url")" || { - handle_curl_error $? - print_error "Failed to fetch the download page. Please download Windows $windows_version ISO manually from $url" - return 1 - } - - # Step 2: Extract Product Edition ID - print_info "Getting Product Edition ID..." - local product_edition_id - product_edition_id="$(echo "$iso_download_page_html" | grep -Eo '<option value="[0-9]+">Windows' | cut -d '"' -f 2 | head -n 1 | tr -cd '0-9' | head -c 16)" - - if [[ -z "$product_edition_id" ]]; then - print_error "Failed to extract product edition ID." - print_error "Please download Windows $windows_version ISO manually from $url" - return 1 - fi - - print_success "Product Edition ID: $product_edition_id" - - # Step 3: Register session ID - print_info "Registering session ID: $session_id" - curl --disable --silent --output /dev/null --user-agent "$user_agent" \ - --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 \ - --http1.1 -- "https://vlscppe.microsoft.com/tags?org_id=y6jn8c31&session_id=$session_id" || { - print_error "Failed to register session ID." - return 1 - } - - # Step 4: Get language SKU ID - print_info "Getting language SKU ID..." - local language_skuid_table_json - language_skuid_table_json="$(curl --disable -s --fail --max-filesize 100K --proto =https --tlsv1.2 --http1.1 \ - "https://www.microsoft.com/software-download-connector/api/getskuinformationbyproductedition?profile=${profile}&ProductEditionId=${product_edition_id}&SKU=undefined&friendlyFileName=undefined&Locale=en-US&sessionID=${session_id}")" || { - handle_curl_error $? - print_error "Failed to get language SKU information." - return 1 - } - - # Extract SKU ID for selected language - local sku_id - - # Try with jq if available (more reliable) - if command -v jq >/dev/null 2>&1; then - sku_id="$(echo "$language_skuid_table_json" | jq -r '.Skus[] | select(.LocalizedLanguage=="'"$language"'" or .Language=="'"$language"'").Id')" - else - # Fallback to grep/cut if jq not available - sku_id="$(echo "$language_skuid_table_json" | grep -o '"Id":"[^"]*","Language":"'"$language"'"' | cut -d'"' -f4)" - - if [[ -z "$sku_id" ]]; then - # Try alternative extraction method - sku_id="$(echo "$language_skuid_table_json" | grep -o '"LocalizedLanguage":"'"$language"'","Id":"[^"]*"' | cut -d'"' -f6)" - fi - fi - - if [[ -z "$sku_id" ]]; then - print_error "Failed to extract SKU ID for $language." - return 1 - fi - - print_success "SKU ID: $sku_id" - - # Step 5: Get ISO download link - print_info "Getting ISO download link..." - local iso_download_link_json - iso_download_link_json="$(curl --disable -s --fail --referer "$url" \ - "https://www.microsoft.com/software-download-connector/api/GetProductDownloadLinksBySku?profile=${profile}&productEditionId=undefined&SKU=${sku_id}&friendlyFileName=undefined&Locale=en-US&sessionID=${session_id}")" - - local failed=0 - - if [[ -z "$iso_download_link_json" ]]; then - print_error "Microsoft servers gave an empty response to the download request." - failed=1 - fi - - if echo "$iso_download_link_json" | grep -q "Sentinel marked this request as rejected."; then - print_error "Microsoft blocked the automated download request based on your IP address." - failed=1 - fi - - if [[ "$failed" -eq 1 ]]; then - print_warning "Please manually download the Windows $windows_version ISO using a web browser from: $url" - print_warning "Save the downloaded ISO to: $WIN_ISO_DIR" - return 1 - fi - - # Extract 64-bit ISO download URL - local iso_download_link - - # Try with jq if available - if command -v jq >/dev/null 2>&1; then - iso_download_link="$(echo "$iso_download_link_json" | jq -r '.ProductDownloadOptions[].Uri' | grep x64 | head -n 1)" - else - # Fallback to grep/cut if jq not available - iso_download_link="$(echo "$iso_download_link_json" | grep -o '"Uri":"[^"]*x64[^"]*"' | cut -d'"' -f4 | head -n 1)" - fi - - if [[ -z "$iso_download_link" ]]; then - print_error "Failed to extract the download link from Microsoft's response." - print_warning "Manually download the Windows $windows_version ISO using a web browser from: $url" - return 1 - fi - - print_success "Got download link: ${iso_download_link%%\?*}" - - # Extract filename from URL - local file_name="$(echo "$iso_download_link" | cut -d'?' -f1 | rev | cut -d'/' -f1 | rev)" - - # If filename couldn't be extracted, use default - if [[ -z "$file_name" || "$file_name" == "$iso_download_link" ]]; then - file_name="windows-$windows_version.iso" - fi - - # Step 6: Download the ISO - print_info "Downloading Windows $windows_version ISO to $WIN_ISO_DIR/$file_name. This may take a while..." - - # Check which download function to use - if type web_get >/dev/null 2>&1; then - web_get "$iso_download_link" "$WIN_ISO_DIR" "$file_name" - else - # Fallback to direct curl download - curl --disable --progress-bar --fail --location --proto '=https' --tlsv1.2 --http1.1 \ - --retry 3 --retry-delay 3 --connect-timeout 30 \ - --output "$WIN_ISO_DIR/$file_name" "$iso_download_link" || { - handle_curl_error $? - return 1 - } - fi - - if [[ $? -ne 0 ]]; then - print_error "Failed to download the Windows $windows_version ISO." - return 1 - fi - - print_success "Successfully downloaded Windows $windows_version ISO to $WIN_ISO_DIR/$file_name" - - # Return the downloaded filename so calling code can use it - echo "$file_name" - return 0 -} - -# Create unattended installation ISO -create_unattended_iso() { - print_info "Creating unattended installation ISO..." - - # Create basic autounattend.xml if it doesn't exist - if [ ! -f "$WIN_ISO_DIR/unattended/autounattend.xml" ]; then - print_info "Creating autounattend.xml..." - cat >"$WIN_ISO_DIR/unattended/autounattend.xml" <<'EOF' -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> - <settings pass="windowsPE"> - <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> - <SetupUILanguage> - <UILanguage>en-US</UILanguage> - </SetupUILanguage> - <InputLocale>0409:00000409</InputLocale> - <SystemLocale>en-US</SystemLocale> - <UILanguage>en-US</UILanguage> - <UserLocale>en-US</UserLocale> - </component> - <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> - <ImageInstall> - <OSImage> - <Compact>false</Compact> - <InstallTo> - <DiskID>0</DiskID> - <PartitionID>3</PartitionID> - </InstallTo> - </OSImage> - </ImageInstall> - <UserData> - <AcceptEula>true</AcceptEula> - </UserData> - <UseConfigurationSet>false</UseConfigurationSet> - <RunSynchronous> - <RunSynchronousCommand wcm:action="add"> - <Order>1</Order> - <Path>cmd.exe /c ">>"X:\diskpart.txt" (echo SELECT DISK=0&echo CLEAN&echo CONVERT GPT&echo CREATE PARTITION EFI SIZE=300&echo FORMAT QUICK FS=FAT32 LABEL="System"&echo CREATE PARTITION MSR SIZE=16)"</Path> - </RunSynchronousCommand> - <RunSynchronousCommand wcm:action="add"> - <Order>2</Order> - <Path>cmd.exe /c ">>"X:\diskpart.txt" (echo CREATE PARTITION PRIMARY&echo SHRINK MINIMUM=1000&echo FORMAT QUICK FS=NTFS LABEL="Windows"&echo CREATE PARTITION PRIMARY&echo FORMAT QUICK FS=NTFS LABEL="Recovery")"</Path> - </RunSynchronousCommand> - <RunSynchronousCommand wcm:action="add"> - <Order>3</Order> - <Path>cmd.exe /c ">>"X:\diskpart.txt" (echo SET ID="de94bba4-06d1-4d40-a16a-bfd50179d6ac"&echo GPT ATTRIBUTES=0x8000000000000001)"</Path> - </RunSynchronousCommand> - <RunSynchronousCommand wcm:action="add"> - <Order>4</Order> - <Path>cmd.exe /c "diskpart.exe /s "X:\diskpart.txt" >>"X:\diskpart.log" || ( type "X:\diskpart.log" & echo diskpart encountered an error. & pause & exit /b 1 )"</Path> - </RunSynchronousCommand> - </RunSynchronous> - </component> - </settings> - <settings pass="specialize"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> - <ComputerName>Win11-VM</ComputerName> - <TimeZone>UTC</TimeZone> - </component> - </settings> - <settings pass="oobeSystem"> - <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> - <InputLocale>0409:00000409</InputLocale> - <SystemLocale>en-US</SystemLocale> - <UILanguage>en-US</UILanguage> - <UserLocale>en-US</UserLocale> - </component> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> - <UserAccounts> - <LocalAccounts> - <LocalAccount wcm:action="add"> - <Name>Admin</Name> - <DisplayName></DisplayName> - <Group>Administrators</Group> - <Password> - <Value>password</Value> - <PlainText>true</PlainText> - </Password> - </LocalAccount> - <LocalAccount wcm:action="add"> - <Name>User</Name> - <DisplayName></DisplayName> - <Group>Users</Group> - <Password> - <Value>password</Value> - <PlainText>true</PlainText> - </Password> - </LocalAccount> - </LocalAccounts> - </UserAccounts> - <AutoLogon> - <Username>Admin</Username> - <Enabled>true</Enabled> - <LogonCount>1</LogonCount> - <Password> - <Value>password</Value> - <PlainText>true</PlainText> - </Password> - </AutoLogon> - <OOBE> - <ProtectYourPC>3</ProtectYourPC> - <HideEULAPage>true</HideEULAPage> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <SkipMachineOOBE>true</SkipMachineOOBE> - <SkipUserOOBE>true</SkipUserOOBE> - </OOBE> - </component> - </settings> -</unattend> -EOF - fi - - # Create the unattended ISO - local iso_tool="" - - if command -v genisoimage >/dev/null 2>&1; then - iso_tool="genisoimage" - elif command -v mkisofs >/dev/null 2>&1; then - iso_tool="mkisofs" - elif command -v xorriso >/dev/null 2>&1; then - iso_tool="xorriso" - fi - - if [ "$iso_tool" != "" ]; then - print_info "Creating unattended ISO using $iso_tool..." - - if [ "$iso_tool" = "xorriso" ]; then - xorriso -as genisoimage -J -r -o "$WIN_ISO_DIR/unattended.iso" "$WIN_ISO_DIR/unattended" - else - "$iso_tool" -J -r -o "$WIN_ISO_DIR/unattended.iso" "$WIN_ISO_DIR/unattended" - fi - - return $? - else - print_warning "No ISO creation tool found (genisoimage, mkisofs, or xorriso)" - print_warning "Creating empty ISO file as fallback" - touch "$WIN_ISO_DIR/unattended.iso" - return 1 - fi -} - -# Download or locate essential files -prepare_files() { - # Find Windows ISO - WINDOWS_ISO_PATH=$(find_windows_iso | tail -n 1 | xargs) - local iso_found=false - - # Check if we found a valid ISO - if [[ -n "$WINDOWS_ISO_PATH" && -f "$WINDOWS_ISO_PATH" ]]; then - print_success "Using Windows ISO: $WINDOWS_ISO_PATH" - iso_found=true - else - print_warning "Windows ISO not found, attempting to download..." - if download_windows_iso; then - # Check again after download attempt - WINDOWS_ISO_PATH=$(find_windows_iso | tail -n 1 | xargs) - if [[ -n "$WINDOWS_ISO_PATH" && -f "$WINDOWS_ISO_PATH" ]]; then - print_success "Using downloaded Windows ISO: $WINDOWS_ISO_PATH" - iso_found=true - fi - fi - fi - - # If we still don't have an ISO, exit - if [[ "$iso_found" != "true" ]]; then - print_error "Could not find or download Windows ISO" - print_info "Please place your Windows ISO file in: $WIN_ISO_DIR" - exit 1 - fi - - # Download VirtIO drivers if missing - if [[ ! -f "$ISO_VIRTIO" ]]; then - print_info "VirtIO drivers ISO not found, downloading..." - download_file "$VIRTIO_ISO_URL" "$ISO_VIRTIO" - else - print_success "VirtIO drivers ISO already exists: $ISO_VIRTIO" - fi - - # Define the directory containing the MSI files - UNATTENDED_DIR="$WIN_ISO_DIR/unattended" - mkdir -p "$UNATTENDED_DIR" - - # Find the latest Spice WebDAVD MSI - SPICE_WEBDAVD_MSI=$(find "$UNATTENDED_DIR" -type f -iname "spice-webdavd-x64*.msi" -exec stat --format="%Y %n" {} \; | sort -n | tail -n 1 | cut -d' ' -f2-) - - # Find the latest Spice VD Agent MSI - SPICE_VDAGENT_MSI=$(find "$UNATTENDED_DIR" -type f -iname "spice-vdagent-x64*.msi" -exec stat --format="%Y %n" {} \; | sort -n | tail -n 1 | cut -d' ' -f2-) - - # Find the latest UsbDk MSI - USBDK_MSI=$(find "$UNATTENDED_DIR" -type f -iname "UsbDk_*_x64.msi" -exec stat --format="%Y %n" {} \; | sort -n | tail -n 1 | cut -d' ' -f2-) - - # Spice Guest Tools + UsbDk (only if missing) - if [[ ! -f "$SPICE_WEBDAVD_MSI" ]]; then - print_info "Downloading Spice WebDAVD..." - curl -L -o "$UNATTENDED_DIR/spice-webdavd-x64-latest.msi" "$SPICE_WEBDAVD_URL" || { - print_error "Failed to download Spice WebDAVD" - return 1 - } - else - print_success "Spice WebDAVD MSI already exists: $SPICE_WEBDAVD_MSI" - fi - - if [[ ! -f "$SPICE_VDAGENT_MSI" ]]; then - print_info "Downloading Spice VD Agent..." - # Try multiple mirrors for spice-vdagent - local spice_mirrors=( - "https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-latest.msi" - "https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-0.10.0.msi" - "https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-0.9.0.msi" - "https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-0.8.0.msi" - "https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-0.7.0.msi" - ) - - local download_success=false - for mirror in "${spice_mirrors[@]}"; do - print_info "Trying mirror: $mirror" - if curl -L -o "$UNATTENDED_DIR/spice-vdagent-x64-latest.msi" "$mirror"; then - # Verify the downloaded file - if [[ -s "$UNATTENDED_DIR/spice-vdagent-x64-latest.msi" ]]; then - download_success=true - break - else - print_warning "Downloaded file is empty, trying next mirror..." - rm -f "$UNATTENDED_DIR/spice-vdagent-x64-latest.msi" - fi - fi - done - - if [[ "$download_success" == "false" ]]; then - print_error "Failed to download Spice VD Agent from all mirrors" - return 1 - fi - else - print_success "Spice VD Agent MSI already exists: $SPICE_VDAGENT_MSI" - fi - - if [[ ! -f "$USBDK_MSI" ]]; then - print_info "Downloading UsbDk..." - curl -L -o "$UNATTENDED_DIR/UsbDk_1.0.22_x64.msi" "$USBDK_URL" || { - print_error "Failed to download UsbDk" - return 1 - } - else - print_success "UsbDk MSI already exists: $USBDK_MSI" - fi - - # Create unattended ISO if it doesn't exist - if [[ ! -f "$ISO_UNATTENDED" ]]; then - create_unattended_iso - else - print_success "Unattended ISO already exists: $ISO_UNATTENDED" - fi -} - -# Locate OVMF firmware files -locate_ovmf() { - OVMF_DIRS=( - "/usr/share/OVMF" - "/usr/share/qemu" - "/usr/lib/qemu" - "/usr/share/edk2" - "/usr/lib/edk2" - "/usr/share/edk2/ovmf" - "/usr/share/edk2-ovmf" - ) - - OVMF_CODE="" - OVMF_VARS="" - - for dir in "${OVMF_DIRS[@]}"; do - [[ -z "$OVMF_CODE" ]] && OVMF_CODE=$(find "$dir" -type f -name "OVMF_CODE.fd" -o -name "edk2-x86_64-code.fd" 2>/dev/null | head -n 1) - [[ -z "$OVMF_VARS" ]] && OVMF_VARS=$(find "$dir" -type f -name "OVMF_VARS.fd" 2>/dev/null | head -n 1) - [[ -n "$OVMF_CODE" && -n "$OVMF_VARS" ]] && break - done - - # Ensure a writable copy of OVMF_VARS.fd - local original_ovmf_vars="$OVMF_VARS" - OVMF_VARS="$FIRMWARE_DIR/OVMF_VARS.fd" - - if [[ ! -f "$OVMF_VARS" && -f "$original_ovmf_vars" ]]; then - print_info "Copying OVMF_VARS.fd to $OVMF_VARS" - cp "$original_ovmf_vars" "$OVMF_VARS" 2>/dev/null || { - print_error "Failed to copy OVMF_VARS.fd!" - exit 1 - } - fi - - # Check if required files exist - if [[ -z "$OVMF_CODE" || ! -f "$OVMF_CODE" ]]; then - print_error "OVMF_CODE.fd not found!" - exit 1 - fi - if [[ ! -f "$OVMF_VARS" ]]; then - print_error "OVMF_VARS.fd not found or could not be copied!" - exit 1 - fi - #} -} - -# Create VM disk image -create_disk() { - # Check if the qcow2 image file exists; if not, create it - if [[ ! -f "$QCOW2_FILE" ]]; then - print_info "Creating $QCOW2_FILE with a size of $VM_SIZE" - qemu-img create -f qcow2 "$QCOW2_FILE" "$VM_SIZE" || { - print_error "Failed to create qcow2 image!" - exit 1 - } - else - print_success "VM disk image already exists: $QCOW2_FILE" - fi -} - -# Generate unique PID file for this instance -generate_pid_file() { - local base_pid_file="$VM_DIR/$VM_NAME.pid" - local pid_file="$base_pid_file" - local counter=1 - - # If the base PID file exists, try to find an available number - while [[ -f "$pid_file" ]]; do - pid_file="${base_pid_file%.pid}-${counter}.pid" - ((counter++)) - done - - echo "$pid_file" -} - -# Start the VM -start_vm() { - # Verify that we have a Windows ISO - if [[ -z "$WINDOWS_ISO_PATH" || ! -f "$WINDOWS_ISO_PATH" ]]; then - print_error "Windows ISO file not found. Cannot start VM." - print_info "Please download Windows 11 ISO and save it to: $WIN_ISO_DIR" - exit 1 - fi - - # Start swtpm - print_info "Starting TPM emulator..." - /sbin/swtpm socket \ - --ctrl type=unixio,path="$TPM_SOCKET" \ - --terminate \ - --tpmstate dir="$TPM_DIR" \ - --tpm2 & - - # Wait for swtpm socket - sleep 1 - - print_info "Starting Windows 11 VM..." - print_info "Using Windows ISO: $WINDOWS_ISO_PATH" - - # Build network options - local network_opts=() - if [[ "$DISABLE_NET" == "true" ]]; then - network_opts=( - "-netdev" "none,id=nic" - "-device" "virtio-net,netdev=nic" - ) - else - if [[ "$ENABLE_SMB" == "true" ]]; then - network_opts=( - "-netdev" "user,id=nic,hostname=$VM_NAME,hostfwd=tcp::$HOST_PORT-:$GUEST_PORT,smb=$SHARED_DIR" - "-device" "virtio-net,netdev=nic" - ) - else - network_opts=( - "-netdev" "user,id=nic,hostname=$VM_NAME,hostfwd=tcp::$HOST_PORT-:$GUEST_PORT" - "-device" "virtio-net,netdev=nic" - ) - fi - fi - - # Run QEMU - /sbin/qemu-system-x86_64 \ - -name "$VM_NAME",process="$VM_NAME" \ - -machine q35,hpet=off,smm=on,vmport=off,accel=kvm \ - -global kvm-pit.lost_tick_policy=discard \ - -global ICH9-LPC.disable_s3=1 \ - -cpu host,+hypervisor,+invtsc,l3-cache=on,migratable=no,hv_passthrough \ - -smp "$SMP_CONFIG" \ - -m "$VM_RAM" \ - -device virtio-balloon \ - -pidfile "$PID_FILE" \ - -rtc base=localtime,clock=host,driftfix=slew \ - -vga none \ - -device virtio-vga-gl,xres=1280,yres=800 \ - -display sdl,gl=on \ - -boot menu=on,splash-time=0,order=d,reboot-timeout=5000 \ - -device virtio-rng-pci,rng=rng0 \ - -object rng-random,id=rng0,filename=/dev/urandom \ - -device qemu-xhci,id=spicepass \ - -chardev spicevmc,id=usbredirchardev1,name=usbredir \ - -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \ - -chardev spicevmc,id=usbredirchardev2,name=usbredir \ - -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2 \ - -chardev spicevmc,id=usbredirchardev3,name=usbredir \ - -device usb-redir,chardev=usbredirchardev3,id=usbredirdev3 \ - -device pci-ohci,id=smartpass \ - -device usb-ccid \ - -chardev spicevmc,id=ccid,name=smartcard \ - -device ccid-card-passthru,chardev=ccid \ - -device usb-ehci,id=input \ - -device usb-kbd,bus=input.0 \ - -k en-us \ - -device usb-tablet,bus=input.0 \ - -audiodev pipewire,id=audio0 \ - -device intel-hda \ - -device hda-micro,audiodev=audio0 \ - "${network_opts[@]}" \ - -global driver=cfi.pflash01,property=secure,value=on \ - -drive if=pflash,format=raw,unit=0,file="$OVMF_CODE",readonly=on \ - -drive if=pflash,format=raw,unit=1,file="$OVMF_VARS" \ - -drive media=cdrom,index=1,file="$ISO_UNATTENDED" \ - -drive media=cdrom,index=0,file="$WINDOWS_ISO_PATH" \ - -drive media=cdrom,index=2,file="$ISO_VIRTIO" \ - -device virtio-blk-pci,drive=SystemDisk \ - -drive id=SystemDisk,if=none,format=qcow2,file="$QCOW2_FILE" \ - -chardev socket,id=chrtpm,path="$TPM_SOCKET" \ - -tpmdev emulator,id=tpm0,chardev=chrtpm \ - -device tpm-tis,tpmdev=tpm0 \ - -monitor unix:"$SOCKET_DIR/$VM_NAME-monitor.socket",server,nowait \ - -serial unix:"$SOCKET_DIR/$VM_NAME-serial.socket",server,nowait -} - -# Check dependencies -check_dependencies() { - # Cache file for dependency checks and VM configuration - local cache_name="windows-vm-${VM_NAME}-${VM_RAM}-${VM_CPU}-${VM_SIZE}" - local cache_file="${HOME}/.cache/${cache_name}.cache" - local cache_dir=$(dirname "$cache_file") - local cache_valid=false - local missing_deps=() - local pkg_manager="" - local pkg_install_cmd="" - local privilege_cmd="" - - # Clean cache if requested - if [[ "$CLEAN_CACHE" == "true" ]]; then - print_info "Cleaning dependency cache..." - rm -f "$cache_file" - fi - - # Create cache directory if it doesn't exist - mkdir -p "$cache_dir" - - # Check if cache is valid (less than 24 hours old) - if [[ -f "$cache_file" ]]; then - local cache_age=$(($(date +%s) - $(stat -c %Y "$cache_file"))) - if [[ $cache_age -lt 86400 ]]; then # 24 hours in seconds - # Read cached configuration - local cached_config - cached_config=$(head -n 1 "$cache_file" 2>/dev/null) - # Compare with current configuration - if [[ "$cached_config" == "${VM_NAME}-${VM_RAM}-${VM_CPU}-${VM_SIZE}" ]]; then - cache_valid=true - else - print_info "VM configuration changed, invalidating cache..." - rm -f "$cache_file" - fi - fi - fi - - # Check KVM group membership - if ! groups | grep -q -E 'kvm|qemu'; then - print_warning "User is not a member of kvm or qemu group" - print_info "You may need to add your user to the kvm group:" - print_info "sudo usermod -aG kvm $USER" - fi - - # Detect package manager and privilege command - if command -v emerge >/dev/null 2>&1; then - pkg_manager="emerge" - pkg_install_cmd="emerge --ask --noreplace" - privilege_cmd="sudo" - # Gentoo package mapping - declare -A pkg_map=( - ["qemu-system-x86_64"]="app-emulation/qemu" - ["qemu-img"]="app-emulation/qemu" - ["swtpm"]="app-crypt/swtpm" - ["genisoimage"]="app-cdr/cdrtools" - ["curl"]="net-misc/curl" - ["uuidgen"]="sys-apps/util-linux" - ["jq"]="app-misc/jq" - ["glxinfo"]="x11-apps/mesa-progs" - ["lspci"]="sys-apps/pciutils" - ["ps"]="sys-process/procps" - ["python3"]="dev-lang/python" - ["mkisofs"]="app-cdr/cdrtools" - ["lsusb"]="sys-apps/usbutils" - ["socat"]="net-misc/socat" - ["spicy"]="app-emulation/spice" - ["xrandr"]="x11-apps/xrandr" - ["zsync"]="net-misc/zsync" - ["unzip"]="app-arch/unzip" - ) - elif command -v apt-get >/dev/null 2>&1; then - pkg_manager="apt-get" - pkg_install_cmd="apt-get install -y" - privilege_cmd="sudo" - # Debian/Ubuntu package mapping - declare -A pkg_map=( - ["qemu-system-x86_64"]="qemu-system-x86" - ["qemu-img"]="qemu-utils" - ["swtpm"]="swtpm-tools" - ["genisoimage"]="genisoimage" - ["curl"]="curl" - ["uuidgen"]="uuid-runtime" - ["jq"]="jq" - ["glxinfo"]="mesa-utils" - ["lspci"]="pciutils" - ["ps"]="procps" - ["python3"]="python3" - ["mkisofs"]="genisoimage" - ["lsusb"]="usbutils" - ["socat"]="socat" - ["spicy"]="spice-client-gtk" - ["xrandr"]="x11-xserver-utils" - ["zsync"]="zsync" - ["unzip"]="unzip" - ) - elif command -v dnf >/dev/null 2>&1; then - pkg_manager="dnf" - pkg_install_cmd="dnf install -y" - privilege_cmd="sudo" - # Fedora package mapping - declare -A pkg_map=( - ["qemu-system-x86_64"]="qemu-system-x86" - ["qemu-img"]="qemu-img" - ["swtpm"]="swtpm" - ["genisoimage"]="genisoimage" - ["curl"]="curl" - ["uuidgen"]="util-linux" - ["jq"]="jq" - ["glxinfo"]="mesa-demos" - ["lspci"]="pciutils" - ["ps"]="procps-ng" - ["python3"]="python3" - ["mkisofs"]="genisoimage" - ["lsusb"]="usbutils" - ["socat"]="socat" - ["spicy"]="spice-gtk-tools" - ["xrandr"]="xorg-x11-server-utils" - ["zsync"]="zsync" - ["unzip"]="unzip" - ) - elif command -v pacman >/dev/null 2>&1; then - pkg_manager="pacman" - pkg_install_cmd="pacman -S --noconfirm" - privilege_cmd="sudo" - # Arch package mapping - declare -A pkg_map=( - ["qemu-system-x86_64"]="qemu" - ["qemu-img"]="qemu" - ["swtpm"]="swtpm" - ["genisoimage"]="cdrtools" - ["curl"]="curl" - ["uuidgen"]="util-linux" - ["jq"]="jq" - ["glxinfo"]="mesa-utils" - ["lspci"]="pciutils" - ["ps"]="procps-ng" - ["python3"]="python" - ["mkisofs"]="cdrtools" - ["lsusb"]="usbutils" - ["socat"]="socat" - ["spicy"]="spice-gtk" - ["xrandr"]="xorg-xrandr" - ["zsync"]="zsync" - ["unzip"]="unzip" - ) - fi - - # List of required commands and their package names - local deps=( - "qemu-system-x86_64" - "qemu-img" - "swtpm" - "genisoimage" - "curl" - "uuidgen" - "jq" - "glxinfo" - "lspci" - "ps" - "python3" - "mkisofs" - "lsusb" - "socat" - "spicy" - "xrandr" - "zsync" - "unzip" - ) - - # If cache is valid, read from it - if [[ "$cache_valid" == "true" ]]; then - print_info "Using cached dependency information..." - # Skip the first line (configuration) and read dependencies - tail -n +2 "$cache_file" | while IFS= read -r dep; do - if ! command -v "$dep" >/dev/null 2>&1; then - missing_deps+=("$dep") - fi - done - else - # Check each dependency and cache the results - print_info "Checking dependencies..." - - # Clear cache file and write current configuration - echo "${VM_NAME}-${VM_RAM}-${VM_CPU}-${VM_SIZE}" >"$cache_file" - - for dep in "${deps[@]}"; do - # Special case for genisoimage/mkisofs - if [[ "$dep" == "genisoimage" ]]; then - if ! command -v genisoimage >/dev/null 2>&1 && ! command -v mkisofs >/dev/null 2>&1; then - missing_deps+=("$dep") - echo "$dep" >>"$cache_file" - fi - # Special case for xdg-user-dirs - elif [[ "$dep" == "xdg-user-dirs" ]]; then - if ! pkg-config --exists xdg-user-dirs; then - missing_deps+=("$dep") - echo "$dep" >>"$cache_file" - fi - # Normal case for other dependencies - elif ! command -v "$dep" >/dev/null 2>&1; then - missing_deps+=("$dep") - echo "$dep" >>"$cache_file" - fi - done - fi - - if [[ ${#missing_deps[@]} -gt 0 ]]; then - print_warning "Missing dependencies:" - for dep in "${missing_deps[@]}"; do - if [[ -n "${pkg_map[$dep]}" ]]; then - print_warning "- $dep (package: ${pkg_map[$dep]})" - else - print_warning "- $dep" - fi - done - - if [[ -n "$pkg_manager" ]]; then - print_info "Detected package manager: $pkg_manager" - read -p "Would you like to install the missing dependencies? (y/N) " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - # Check for privilege command - if ! command -v "$privilege_cmd" >/dev/null 2>&1; then - print_error "Privilege command ($privilege_cmd) not found" - print_info "Please install the missing packages manually" - else - # Install missing packages - print_info "Installing missing dependencies..." - local pkgs_to_install=() - for dep in "${missing_deps[@]}"; do - if [[ -n "${pkg_map[$dep]}" ]]; then - pkgs_to_install+=("${pkg_map[$dep]}") - fi - done - "$privilege_cmd" "$pkg_install_cmd" "${pkgs_to_install[@]}" - - # Clear cache after installation - rm -f "$cache_file" - fi - else - print_warning "Continuing without installing dependencies. Some features may not work correctly." - fi - else - print_warning "No supported package manager found" - print_info "Please install the missing packages manually" - fi - else - print_success "All required dependencies are installed" - fi -} - -# Main execution -check_dependencies - -if [[ "$CHECK_DEPS_ONLY" == "true" ]]; then - exit 0 -fi - -if [[ "$DOWNLOAD_ISO_ONLY" == "true" ]]; then - download_windows_iso "$WINDOWS_VERSION" - exit 0 -fi - -# Generate unique PID file for this instance -PID_FILE=$(generate_pid_file) -print_info "Using PID file: $PID_FILE" - -prepare_files -locate_ovmf -create_disk -start_vm |
