#!/bin/bash # shellcheck shell=bash if [[ -z "${BASH_VERSINFO[0]:-}" ]]; then echo "SHELL ENV ERROR: You must use a BASH Shell to load this library. Exiting..." exit 255 fi export RTD_VERSION="2.37" : <<'Library_Documentation' :: R T D F u n c t i o n L i b r a r y :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// Linux //::::::: :: Author(s): SLS, KLS, NB. Buffalo Center, IA & Avarua, Cook Islands :: Version: 2.37 :: :: :: Purpose: To collect and enable the use of code snippets in other scripts. :: To document these thoroughly so that they may be useful for learning BASH. :: Usage: call this file using the "source" statement in bash. :: :: This script is shared in the hopes that :: someone will find it useful. :: :: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: .--. .---. .-. .---|--| .-. | A | .---. |~| .--. .--|===|Ch|---|_|--.__| S |--|:::| |~|-==-|==|---. |%%|NT2|oc|===| |~~|%%| C |--| |_|~|CATS| |___|-. | | |ah|===| |==| | I | |:::|=| | |GB|---|=| | | |ol| |_|__| | I |__| | | | | |___| | |~~|===|--|===|~|~~|%%|~~~|--|:::|=|~|----|==|---|=| ^--^---'--^---^-^--^--^---'--^---^-^-^-==-^--^---^-' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --- To see options to use this library type "bash _rtd_library --help" --- To see useful documentation on each function in this library in a Terminal or remote ssh: "bash _rtd_library --devhelp" --- To see useful documentation on each function in this library in GTK (local desktop): "bash _rtd_library --devhelp-gtk" Use Google Coding standards: In general any function that is not both obvious and short must be commented. Any function in a library must be commented regardless of length or complexity. It should be possible for someone else to learn how to use your program or to use a function in your library by reading the comments (and self-help, if provided) without reading the code. All function comments should describe the intended function behavior using: 1 Description of the function. 2 Globals: List of global variables used and modified. 3 Arguments: Arguments taken. 4 Outputs: Output to STDOUT or STDERR. 5 Returns: Returned values other than the default exit status of the last command run. Advice: As a "best practice" working with this file, given the size and complexities, it is better to write a new function in an external script and use the "source" statement to include this library in said script, so that all the other functions here are available to use in the new function. . ├── 📜 Standard Interactions & UI │ ├── dialog::* (TUI dialogs: notice, error, progress, yes/no) │ ├── yad::* (GUI dialogs using YAD) │ ├── zenity::* (GUI dialogs using Zenity) │ └── term::* (Terminal animations and formatted output) │ ├── ⚙️ System & OEM Management │ ├── system::* (Service management, logging, ISO creation, sys-info) │ ├── oem::* (Branding, theming, creating launchers, resealing) │ ├── gnome::* (GNOME-specific tweaks: Dash-to-Panel, Nautilus, fonts) │ └── security::* (Firewall, encryption, hardening, malware scanning) │ ├── 📦 Software Management │ ├── software::* (Install/remove packages, manage Flatpak/Snap, update system) │ └── dependency::* (Check for commands, OS, desktop environment) │ ├── 🌐 Network Operations │ ├── network::* (Check internet, get public IP, rsync wrappers) │ └── ssh::* (Manage SSH keys) │ ├── 🖥️ Virtualization (KVM) │ ├── kvm::* (Create, clone, and manage KVM virtual machines) │ ├── kvm::cicd::* (Automate VM config with cloud-init and Ansible) │ ├── kvm::util::* (VM naming and configuration helpers) │ └── whonix::* (Specific functions to deploy Whonix Gateway/Workstation VMs) │ ├── 📝 Templates & Configuration │ ├── template::* (Generate config files: AutoYast, Kickstart, preseed, etc.) │ └── library::* (Core library functions, path normalization) │ └── 🛠️ Miscellaneous Tools ├── tool::* (Compress/recompress files, test ISO boot media) ├── disk::* (Device re-encryption) └── fedora::*, ubuntu::*, mint::* (Distro-specific ISO downloaders) :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Functions defined in this library: global: 1 add_gnome3_favorite_app ; Function to add a new favorite app to the gnome favorites bar. 2 check_java ; Check java. 3 create_physical_media_from_iso ; Create physical media from iso. 4 display_gui ; Displays a GUI dialog box with the given message. 5 display_software_installation_choices_gtk ; Function to display the software install otions. All software option are listed in. 6 find_active_network_interface ; Detect the active network interface and export it for later use. 7 install_software ; Simple function to help installing software on several linux distributions. 8 InstallSoftwareFromRepo ; Function to simplify the installation of software by including all display and. 9 main ; Entry point when running the library as a script. 10 minecraft_update ; Ensure the Minecraft home directory exists. 11 rtd_oem_turn_on_gui_network_management ; Function to set NetworkManager by default to manage networking. 12 rtd_oem_ubuntu_auto_install_iso_builder ; Legacy entrypoint; use the OEM task implementation. 13 rtd_server_setup_choices_productivity ; Function to display terminal software installation options. This will install. 14 rtd_server_setup_choices_services ; Function to display server installation options. This will install software that is usefull. 15 run_minecraft_server_manager ; Start byobu multi screen app. 16 setup_minecraft_root ; Setup and initiate the location of the mincraft server. 17 write_error ; Write error. 18 write_host ; Write host. 19 write_information ; Write information. 20 write_status ; Write status. 21 write_warning ; Write warning. dependency: 22 dependency::check_hardware_virtualization_support ; Checks if the hardware supports virtualization (VT-x or AMD-V). 23 dependency::check_if_running_in_vm ; Checks if the system is running inside a virtual machine. 24 dependency::command_exists ; Checks if specified commands exist on the system and installs missing ones. 25 dependency::desktop ; Identifies the currently running desktop environment. 26 dependency::file ; Checks for a Bash library or script file and sources it. 27 dependency::os_linux ; Checks if the current operating system is Linux. 28 dependency::search_local ; Search local. 29 dependency::virtualization ; Checks for required components for making virtual machines and verifies hardware support for virtualization. desktop: 30 desktop::apply_user_tweaks ; Apply user tweaks. 31 desktop::enable_firefox_pip_global ; Enable firefox pip global. dialog: 32 dialog::check_menu_availability ; First discover what menu system is installed. Some systems use "dialog" and. 33 dialog::copy_file_progress ; Displays a file copy progress dialog. 34 dialog::copy_with_progress ; Function to display a progress bar while copying a large file to a destination. 35 dialog::display_cmd_output ; Displays the output of a command in a dialog box. 36 dialog::display_error ; Displays an error notice using a dialog box. 37 dialog::display_notice ; Displays an information notice using a dialog box. 38 dialog::display_result ; Displays the contents of the variable "result" in a message box. 39 dialog::display_summary_message ; Function to read a variable "result" and display its contents. The purpose of this function. 40 dialog::prompt_yes_no ; Displays a Yes/No prompt using a dialog box. disk: 41 disk::reencrypt_device ; Reencrypt device. fedora: 42 fedora::get_fedora_netinst_iso_url ; Get fedora netinst iso url. 43 fedora::get_latest_release_version ; Get latest release version. github: 44 github::clone_repo_user ; Clone repo user. 45 github::list_all_user_repositories ; List all user repositories. gnome: 46 gnome::_apply_gtk4_theme ; Write a GTK4 settings.ini with the requested theme/icon and dark. 47 gnome::_apply_terminal_preferences ; Apply consistent GNOME Terminal profile settings across the default. 48 gnome::_reload_shell_theme ; Request a GNOME Shell reload so theme changes take effect. No-op. 49 gnome::_reset_ui_theme_settings ; Reset GNOME theme-related settings and remove GTK4 overrides to. 50 gnome::configure_dash_to_dock ; Configure Dash-to-Dock with OEM defaults (layout, indicators,. 51 gnome::configure_dash_to_panel ; Configure Dash-to-Panel with OEM defaults including icon sizing. 52 gnome::configure_nautilus ; Apply Nautilus usability defaults (zoom level, executable prompts,. 53 gnome::ensure_window_buttons_visible ; Force-enable window controls (minimize/maximize/close) and allow. 54 gnome::organize_overlay_menu ; Organize the GNOME application grid into OEM categories following. 55 gnome::set_basic_extensions_enabled ; Set basic extensions enabled. 56 gnome::set_better_font_smoothing_for_user ; Tune GNOME font smoothing (hinting, antialiasing, subpixel order). 57 gnome::set_better_usability_for_user ; Apply general GNOME usability tweaks (mouse acceleration, volume,. 58 gnome::set_power_configuraton_for_user ; Apply OEM power and interface defaults (sleep, tracker indexer,. 59 gnome::set_startup_sound ; Configure the GNOME startup sound for the current user by. 60 gnome::set_tilix_ui_tweaks_for_user ; Configure Tilix and GNOME Terminal with OEM defaults and import. 61 gnome::set_ui_common_tweaks_for_user ; Convenience alias that forwards to gnome::set_ui_tweaks_for_user. 62 gnome::set_ui_corporate_crisp_tweaks_for_user ; Apply a clean corporate-inspired GNOME theme (Arc) for the. 63 gnome::set_ui_mac_tweaks_for_user ; Apply a macOS-inspired GNOME theme (WhiteSur) for the current. 64 gnome::set_ui_moca_tweaks_for_user ; Apply an eye-friendly mocha-inspired GNOME theme (Vimix/Flatery). 65 gnome::set_ui_tweak_no_media_error ; Notify the user that theme assets are missing and optionally. 66 gnome::set_ui_tweaks_for_user ; Apply the core OEM GNOME tweaks for the current desktop user. 67 gnome::set_ui_win10_tweaks_for_user ; Apply a Windows 10-inspired GNOME theme for the current desktop. kde: 68 kde::_apply_lnf_cmd ; Apply lnf cmd. 69 kde::_kwriteconfig_cmd ; Return kwriteconfig6 when present, otherwise kwriteconfig5. 70 kde::_plasma_version_major ; Plasma version major. 71 kde::_reload_shell ; Reload shell. 72 kde::apply_window_rules ; Apply window rules. 73 kde::set_color_scheme ; Set color scheme. 74 kde::set_cursor_theme ; Set cursor theme. 75 kde::set_global_look_and_feel ; Set global look and feel. 76 kde::set_icon_theme ; Set icon theme. 77 kde::set_layout_panel ; Set layout panel. 78 kde::set_startup_apps ; Set startup apps. 79 kde::set_wallpaper ; Set wallpaper. 80 kde::tune_fonts_antialias ; Tune fonts antialias. kvm: 81 kvm::backup_all_running_vm ; Backup all running vm. 82 kvm::cicd::_create_nocloud_iso ; Create nocloud iso. 83 kvm::cicd::_render_extra_vars ; Render extra vars. 84 kvm::cicd::_render_meta_data ; Render meta data. 85 kvm::cicd::_render_user_data ; Render user data. 86 kvm::cicd::configure_vm_with_ansible_pull ; Configure vm with ansible pull. 87 kvm::cleanup_unused_qcow_images ; Clean up unused qcow images. 88 kvm::cleanup_virtual_floppy_images ; Clean up virtual floppy images. 89 kvm::clone_server_template_vm ; Clone server template vm. 90 kvm::clone_template_vm::_build_customize_args ; Build customize args. 91 kvm::clone_template_vm::_clone_from_category ; Clone from category. 92 kvm::clone_template_vm::_display_template_label ; Display template label. 93 kvm::clone_template_vm::_format_name_component ; Format name component. 94 kvm::clone_vdi_template_vm ; Clone vdi template vm. 95 kvm::create_expanding_vm_hardisk ; Create expanding vm hardisk. 96 kvm::get_almalinux_boot_iso ; Get almalinux boot iso. 97 kvm::get_fedora_workstation_iso ; Get fedora workstation iso. 98 kvm::get_kali_iso ; Get kali iso. 99 kvm::get_vm_config_preferences ; Retrieves VM configuration values from a configuration file or defaults. 100 kvm::get_vm_size_preferences ; Loads VM sizing defaults from _locations.info or internal fallbacks and. 101 kvm::get_zorin_iso ; Downloads the latest Zorin OS ISO file for KVM if not already present. 102 kvm::make_vm_now_from_debian_org ; Function to create a Debian KVM virtual michine disk and define a VM. This function should be. 103 kvm::make_vm_now_from_fedora_org ; Function to create a Fedora KVM virtual michine disk and define a VM. This function should be. 104 kvm::make_vm_now_from_kali_org ; Function to create a Debian KVM virtual michine disk and define a VM. This function should be. 105 kvm::make_vm_now_from_microsoft ; Create vm now from microsoft. 106 kvm::make_vm_now_from_opensuse_org ; Creates a SUSE KVM virtual machine disk and defines a VM. This function is intended to be. 107 kvm::make_vm_now_from_redhat_com ; Function to create a Alma Linux KVM virtual michine disk and define a VM. This function should be. 108 kvm::make_vm_now_from_ubuntu_com ; Create vm now from ubuntu com. 109 kvm::make_vm_now_from_zorin ; Creates a KVM virtual machine template using a Zorin OS ISO. 110 kvm::mount_local_folder_to_guest ; Mount local folder to guest. 111 kvm::util::config_label ; Build a human-friendly configuration label (e.g. "Minecraft-Server") from a raw token. 112 kvm::util::read_common_options ; Function to read common options for KVM virtual machine creation. This function processes. 113 kvm::util::read_distro_options ; Function to read distribution specific options for KVM virtual machine creation. This function processes. 114 kvm::util::set_vm_name ; Set the VM name consistently across functions. 115 kvm::util::validate_vm_name ; Validate a VM name according to hostname rules. 116 kvm::wait_for_domain_definition ; Wait for domain definition. 117 kvm::wait_for_domain_start ; Wait for domain start. library: 118 library::__build_header_desc_map ; Build header desc map. 119 library::__cache_dir ; Resolve and create the cache directory used by RTD helper caches. 120 library::__desc_cache_file ; Return the cache file path used to persist function descriptions. 121 library::__get_function_description ; Get function description. 122 library::__load_desc_cache ; Load cached header/description maps when the cache is newer than this script. 123 library::__load_zformat_cache ; Emit cached --zformat lines when the cache is fresh. 124 library::__save_desc_cache ; Persist header/description maps to disk for faster subsequent runs. 125 library::__save_zformat_cache ; Persist the most recent --zformat lines to disk for reuse. 126 library::__zformat_cache_file ; Return the cache file path for cached --zformat output. 127 library::apply_rtd_defaults ; Apply sane default values to core RTD paths and URLs using precedence. 128 library::check_status ; Check status. 129 library::envcheck_report ; Display how and where the library was loaded for support/debugging. 130 library::list_loaded_internal_functions ; List loaded internal functions. 131 library::list_loaded_software_functions ; Function to list all software (_rtd_recipes) functions loaded... for debugging/support purposes. mint: 132 mint::get_mint_lmde_iso ; Get mint lmde iso. network: 133 network::check_inet_access ; Check inet access. 134 network::get_oem_test_ips ; Return test IPs as newline-separated list honoring _OEM_TEST_IPS override. 135 network::rsync_download ; Rsync download. 136 network::rsync_upload ; Rsync upload. 137 network::whats_my_external_ip ; Whats my external ip. 138 network::whats_my_ipinfo ; Whats my ipinfo. oem: 139 oem::check_boot_splash_screen_enable ; OEM function to enable splash screen on boot if desktop is indicated in. 140 oem::create_single_launcher ; Function to create a single .desktop file for an application. 141 oem::deploy_themes ; Downloads and deploys themes from GitHub. 142 oem::distro_release_upgrade ; Distro release upgrade. 143 oem::register_all_tools ; Function to register all OEM scripts on the current device. 144 oem::register_wallpapers_for_gnome ; Validate the input directory. 145 oem::remove_non_western_latin_fonts ; a simple function to remove known. 146 oem::rtd_reset_default_environment_config ; Rtd reset default environment config. 147 oem::rtd_tools_make_launchers ; Rtd tools make launchers. 148 oem::rtd_tools_make_launchers_from_locations ; Rtd tools make launchers from locations. 149 oem::setup_brand_splash_screen ; oem::setup_brand_splash_screen. 150 oem::setup_choices_server ; Function to display legacy installation options. This will install software that is usefull. 151 oem::task::auto_install_iso_debian ; Auto install iso debian. 152 oem::task::auto_install_iso_ubuntu ; Auto install iso ubuntu. 153 oem::task::auto_install_iso_windows ; Auto install iso windows. 154 oem::task::auto_install_iso_zorin ; Auto install iso zorin. 155 oem::task::debian::inject_initrd ; Inject initrd. 156 oem::task::debian::tweak_boot_cfg ; Tweak boot cfg. 157 oem::task::iso::collect_boot_cfg_paths ; Collect boot cfg paths. 158 oem::task::iso::detect_boot_args ; Detect boot args. 159 oem::task::iso::download_url ; Download url. 160 oem::task::iso::ensure_grub_splash_fallback ; Ensure grub splash fallback. 161 oem::task::iso::extract_iso ; Extract iso. 162 oem::task::iso::fetch_url ; Fetch url. 163 oem::task::iso::find_cached_iso ; Find cached iso. 164 oem::task::iso::force_ubiquity_preseed ; Force ubiquity preseed. 165 oem::task::iso::format_output_name ; Format output name. 166 oem::task::iso::inject_initrd ; Inject initrd. 167 oem::task::iso::inject_preseed_boot_params ; Inject preseed boot params. 168 oem::task::iso::post_build_menu ; Post build menu. 169 oem::task::iso::rebuild_initrd_simple ; Rebuild initrd simple. 170 oem::task::iso::repack_iso ; Repack iso. 171 oem::task::iso::resolve_debian_netinst ; Resolve debian netinst. 172 oem::task::iso::sanitize_label ; Sanitize label. 173 oem::task::iso::sanitize_volume_id ; Sanitize volume id. 174 oem::task::iso::tweak_autoinstall_menu_labels ; Tweak autoinstall menu labels. 175 oem::task::iso::update_md5sum_entries ; Update md5sum entries. 176 oem::task::ubuntu::inject_cloud_config ; Inject cloud config. 177 oem::ventoy::brand_media ; Brand media. 178 oem::ventoy::classify_iso ; Classify iso. 179 oem::ventoy::copy_isos ; Copy isos. 180 oem::ventoy::create_ext4_data_partition ; Create ext4 data partition. 181 oem::ventoy::create_usb ; Create usb. 182 oem::ventoy::detect_data_partition ; Detect data partition. 183 oem::ventoy::download ; Download. 184 oem::ventoy::find_brand_wallpaper ; Find brand wallpaper. 185 oem::ventoy::prepare_folders ; Prepare folders. 186 oem::ventoy::resolve_latest_version ; Resolve latest version. 187 oem::ventoy::select_usb_device ; Select usb device. 188 oem::ventoy::setup_usb ; Setup usb. pause: 189 pause::a_given_time ; A given time. 190 pause::for_input ; For input. security: 191 security::change_disk_pass ; Function to change the passphrase fo an encrypted storage device. 192 security::check_if_password_pOwned ; Check if password pOwned. 193 security::configure_auditd ; Function to install and configure auditd for system auditing. 194 security::configure_clamav ; Configure clamav. 195 security::configure_fail2ban ; Configure fail2ban. 196 security::configure_rkhunter ; Function to install and configure RKHunter (Rootkit Hunter) for system security. 197 security::enable_firewall ; Enable firewall. 198 security::encrypt_disk_with_luks ; Encrypt disk with luks. 199 security::ensure_admin ; Ensures the script is executed with administrative (root) privileges, allowing. 200 security::harden_ubuntu ; Harden ubuntu. 201 security::install_AIDE ; Function to install and configure AIDE (Advanced Intrusion Detection Environment). 202 security::scan_for_malware ; Scan for malware. 203 security::secure_password_policy ; Function to enforce a secure password policy on the system. 204 security::sysctl_hardening ; Sysctl hardening. software: 205 software::add_gnome_extensions ; Add gnome extensions. 206 software::add_native_package ; Add native package. 207 software::add_software_task ; Display executed task and echo ON/NOK based on sucess. 208 software::check_native_package_dependency ; Check native package dependency. 209 software::determine_package_name_from_cmd ; Function to determine the package name from the command line. 210 software::display_bundle_install_choices_gtk ; Function to display the software install otions. All software option are listed in. 211 software::display_bundle_removal_choices_gtk ; Function to display the Software Prodictivity Bundles removal otions. All software options are listed in. 212 software::ensure_flatpak_package_managment ; Function to ensure that flatpak is installed and flathup enabled. 213 software::ensure_gnome_software_store_available ; Function to ensure that flatpak is installed and flathup enabled. 214 software::ensure_restricted_codecs ; simple function to ensure that restricted codecs are available on the system. 215 software::ensure_snap_package_managment ; Function to ensure that snap is installed. 216 software::is_native_package_available ; Function to chek if a package is available in whetever repository, and. 217 software::is_native_package_installed ; Function to check if a piece of software is installed. This function will first check. 218 software::list_bundles ; Function to list all software bundles defined in _rtd_recipes that are either installable or removable. 219 software::native_management_availability_check ; Native management availability check. 220 software::package_kit::add_package ; Function to simplify the installation of software by including all display and. 221 software::package_kit::remove_package ; Function to simplify the installation of software by including all display and. 222 software::remove_native_software_package ; Remove native software package. 223 software::rtd_ppa_checker ; Rtd ppa checker. 224 software::set_install_command ; Set install command. 225 software::update_all_ui ; Update all ui. 226 software::update_system ; Update system. 227 software::update_system_txt ; Update system txt. 228 software::vendor_download_and_install ; Function by Nate Beaken to ease and make consistent the downloading of the non repository. 229 software::zypper_add_repo ; Zypper add repo. ssh: 230 ssh::ensure_key_installed_on_remote ; Ensure key installed on remote. 231 ssh::ensure_user_ssh_key ; Ensure user ssh key. system: 232 system::_disable_service ; Disable service. 233 system::_enable_service ; Function to enable and start a systemd service. 234 system::_turn_on_gui_network_management ; Configures the system to use NetworkManager for network configuration,. 235 system::add_or_remove_login_script ; Add or remove login script. 236 system::check_file_limits ; Check file limits. 237 system::check_required_variables ; Function to check for the presence and non-emptiness of a list of variables. 238 system::cleanup_and_finish ; Function to remove all temporary file locations left over from building. 239 system::create_iso_image_debian ; Function to generate the new ISO file from the extracted and. 240 system::create_physical_media_from_ubuntu_iso ; Create physical media from ubuntu iso. 241 system::create_swapfile ; Function to create a swapfile and enable it automatically. 242 system::detect_session ; Detects the current session type (TTY, SSH, GUI, Wayland). 243 system::determine_logfile ; Determine logfile. 244 system::display_spinner ; Simple function to display a spinner in the terminal. 245 system::distribution_type ; Distribution type. 246 system::download_and_manipulate_iso_debian ; Legacy entrypoint; use the OEM task implementation. 247 system::ensure_directory_exists ; Function to ensure a directory exists, creating it if necessary. 248 system::find_download_ubuntu_iso ; Find download ubuntu iso. 249 system::find_vm_bridge ; Locate a usable network for VM networking. Prefer a host bridge with a physical member; otherwise fall back to a libvirt network (preferring "default"). Logs diagnostics, returning 1 only when nothing usable is found. 250 system::find_vm_bridge_gemini ; Locate a usable network for VM networking. Prefer a host bridge with a physical member; otherwise fall back to a libvirt network (preferring "default"). Logs diagnostics, returning 1 only when nothing usable is found. 251 system::generate_autoyast_file ; Generate autoyast file. 252 system::generate_cloudconfig ; Generate cloudconfig. 253 system::generate_ks_cfg_file ; Generates an installation configuration file (kickstart) for Fedora/Red Hat. 254 system::generate_report_disk_space_used_by_directory ; Function to generate a report for folders' disk space use. 255 system::get_Windows_Product_Key ; Function to retrieve a Windows product key from the BIOS. This assumes that the OEM. 256 system::install_missing_commands ; Installs missing commands based on the distribution type. 257 system::io_on_notify_wait ; Function that, when called, will wait for a disk change. 258 system::keyboard_set_layout ; Keyboard set layout. 259 system::laptop_detect ; Determine if the current system appears to be a laptop without relying on the laptop-detect utility. 260 system::log_item ; Log item. 261 system::make_preseed_cfg ; Function to write out a debina preeseed file to a location requested by the first parameter. 262 system::make_system_recovery_partition ; Incomplete function to build an OEM rescue partition. 263 system::oem_autounlock_disk ; Setup automatic unlocking of the encrypted system disk. 264 system::optimize_harddrive ; Optimize harddrive. 265 system::optimize_startup ; Optimize startup. 266 system::prepare_environment_for_iso_creation ; Function to check that all dependencies are available for manipulating the. 267 system::preseed_to_ubuntu_ks_cfg ; Generates a preseed section [Ubuntu only] (ks.cfg). 268 system::preserve_graphical_session_environment ; Ensure graphical environment variables are set when running as root after escalation. 269 system::process_vm_opt_args ; Process vm opt args. 270 system::read_config ; This function reads a configuration file with key-value pairs. 271 system::remove_old_kernel ; Purge older Linux kernel packages, keeping the currently running kernel. 272 system::restart_sound ; Restarts the user's sound server (PipeWire or PulseAudio). 273 system::rtd_oem_find_live_release ; This function will return the URL for the version of Debian, Ubuntu server or Destktop requested. 274 system::rtd_oem_reseal ; Rtd oem reseal. 275 system::rtd_oem_reseal::_finalize_shutdown ; Finalize shutdown. 276 system::rtd_oem_reseal::_install_guest_additions ; Install guest additions. 277 system::rtd_oem_reseal::_prepare_debian ; Prepare debian. 278 system::rtd_oem_reseal::_prepare_fedora ; Prepare fedora. 279 system::rtd_oem_reseal::_prepare_suse ; Prepare suse. 280 system::rtd_oem_reseal::_prepare_ubuntu_like ; Prepare ubuntu like. 281 system::rtd_oem_reseal::_virtualization_context ; Virtualization context. 282 system::run_command_in_gnome_user_session ; Function to do a reverse sudo back to teh original Gnome user who called upon sudo. 283 system::set_oem_elevated_privilege_gui ; Description. 284 system::toggle_oem_auto_elevated_privilege ; Toggles passwordless sudo privileges for a specified user. 285 system::toggle_oem_auto_login ; Toggle oem auto login. 286 system::tune_system_power_profile ; Tuned is a Linux feature that monitors a system and optimizes its performance. 287 system::update_config ; This function updates a configuration file with key-value pairs. 288 system::validate_parameters ; Function to validate that all parameters match the pattern --option "value". 289 system::wait_for_internet_availability ; Waits for an active internet connection before proceeding. template: 290 template::Agama_json ; Agama json. 291 template::autounattend_xml ; Autounattend xml. 292 template::AutoYast_xml ; Autoyast xml. 293 template::cloud_config ; Cloud config. 294 template::config_menu_cmd ; Config menu cmd. 295 template::kickstart_cfg ; Kickstart cfg. 296 template::minecraft_server_launcher ; Minecraft server launcher. 297 template::preseed_cfg::auto_disk_layout ; Auto disk layout. 298 template::preseed_cfg::early_command ; Early command. 299 template::preseed_cfg::expert_recipe ; Expert recipe. 300 template::preseed_cfg::late_command ; Late command. 301 template::preseed_cfg::main ; Entry point when running the library as a script. 302 template::rtd_me_sh_cmd ; Rtd me sh cmd. term: 303 term::animate_while_command ; Displays an animation during the execution of a silent command. 304 term::err_no_menu_system_found ; Function to handle the error condition if a manu system is not found on the system. 305 term::set_colors ; Set colors for prompting on screen in human readable variables. These will be set globally. 306 term::start_animation ; Start animation. 307 term::stop_animation ; Stop animation. 308 term::task_exec_list_output ; Task exec list output. tool: 309 tool::compress_all_items_here ; Function to compress the contents of the present working directory. 310 tool::compress_provided_items ; Function to compress the contents of the present working directory. 311 tool::recompress_all_items_in_folder ; Function to recompress all archive files in the current directory to a specified format. 312 tool::recompress_provided_items ; Function to recompress specified files to a target compression format. 313 tool::test_iso_boot_media ; Function to test a created ISO file by booting it in a temporary VM using QEMU. 314 tool::up_2_date ; Function to simplify updating system completely. At present this function sets the. ubuntu: 315 ubuntu::download_iso ; Downloads the specified Ubuntu ISO (Desktop or Server) based on the provided flavor, version, and type. 316 ubuntu::enable_plymouth_theme ; Detects the Ubuntu spin (flavor) and ensures the appropriate. 317 ubuntu::get_latest_release_version ; Get latest release version. 318 ubuntu::get_target_version ; Get target version. util: 319 util::add_iso_to_ventoy ; Function to add an ISO file to a Ventoy USB drive for multiple boot options. 320 util::validate_heredoc_tabs_only ; Validate heredoc tabs only. whonix: 321 whonix::add_extra_workstation ; Create an additional workstation VM overlaying an existing base disk. 322 whonix::current_vm_version ; Current vm version. 323 whonix::define_vms ; Define or refresh Whonix Gateway/Workstation VMs against target images. 324 whonix::detect_image_owner ; Determine the appropriate owner:group for libvirt images. 325 whonix::discover_bundle ; Discover the latest Whonix libvirt bundle (prefers GUI/LXQt) and checksum. 326 whonix::download_bundle ; Fetch the Whonix bundle if not already present locally. 327 whonix::download_with_verify ; Download a file with retries and optional SHA-512 verification. 328 whonix::ensure_networks_defined ; Define Whonix virtual networks idempotently. 329 whonix::ensure_networks_running ; Start Whonix virtual networks if they are not active. 330 whonix::extract_archive ; Extract the Whonix libvirt archive only when images/XMLs are missing. 331 whonix::init_context ; Initialize context. 332 whonix::maybe_skip_install ; Skip all work when existing VMs are already at/above the target version unless refresh/add is requested. 333 whonix::prepare_workdir ; Ensure the working directory is ready for the target bundle and clear stale bundles. 334 whonix::stage_images ; Move or reuse Whonix qcow2/raw images in the libvirt images directory. 335 whonix::version_ge ; Version ge. yad: 336 yad::display_cmd_output ; Displays the output of a command in a YAD box. 337 yad::display_file ; Displays the content of a text file in a Zenity window. 338 yad::display_info ; Displays an information notice using a Zenity info box. 339 yad::display_progressbar_pulsating ; Displays the output of a command in a pulsating progress box. 340 yad::display_url ; Displays the content of a URL in a GUI using Zenity. zenity: 341 zenity::display_file ; Displays the content of a text file in a Zenity window. 342 zenity::display_info ; Displays an information notice using a Zenity info box. 343 zenity::display_url ; Displays the content of a URL in a GUI using Zenity. Library_Documentation ################################################################################################ # |>>> |>>> # | |>>> |>>> | # * | | * # / \ * * / \ # /___\ _/ \ / \_ /___\ # [ ] |/ \_________/ \| [ ] # [ I ] / \ / \ [ I ] # [ ]_ _ _ / \ / \ _ _ _[ ] # [ ] U U | {#########} {#########} | U U [ ] # [ ]====/ \=======/ \=======/ \====[ ] # [ ] | | I |_ _ _ _| I | | [ ] # [___] |_ _ _ _ _ _| | U U U | |_ _ _ _ _ _| [___] # \===/ I | U U U U U | |=======| | U U U U U | I \===/ # \=/ |===========| I | + W + | I |===========| \=/ # | I | | |_______| | | I | # | | | ||||||||| | | | # | | | I ||vvvvv|| I | | | # _-_-|______|-----------|_____|| ||_____|-----------|______|-_-_ # /________\ /______|| ||______\ /________\ # |__________|-------|________\_____/________|-------|__________| # ################################################################################################ # # 888 d8b 888 # 888 Y8P 888 # 888 888 # 888 888 88888b. 888d888 8888b. 888d888 888 888 # 888 888 888 "88b 888P" "88b 888P" 888 888 # 888 888 888 888 888 .d888888 888 888 888 # 888 888 888 d88P 888 888 888 888 Y88b 888 # 88888888 888 88888P" 888 "Y888888 888 "Y88888 # 888 # Y8b d88P # "Y88P" # .d8888b. 888 888 d8b # d88P Y88b 888 888 Y8P # Y88b. 888 888 # "Y888b. .d88b. 888888 888888 888 88888b. .d88b. .d8888b # "Y88b. d8P Y8b 888 888 888 888 "88b d88P"88b 88K # "888 88888888 888 888 888 888 888 888 888 "Y8888b. # Y88b d88P Y8b. Y88b. Y88b. 888 888 888 Y88b 888 X88 # "Y8888P" "Y8888 "Y888 "Y888 888 888 888 "Y88888 88888P' # 888 # Y8b d88P # "Y88P" ################################################################################################ # Disable unset variable error checking because we are using default values :-"default_value" set +u # Define the name of the library files required for this script # For flexibility we use variables with default values that can be overridden by the script that # sources this library by simply setting them in the parent environment. : ${_branding_info:="_branding.info"} : ${_locations_info:="_locations.info"} : ${_rtd_recipies_info:="_rtd_recipies.info"} # Online source for scripts and configuration : ${_src_url="https://github.com/${_GIT_PROFILE:-vonschutter}/RTD-Setup/raw/main/core/${1}"} # load global information: declare -a _OEM_dependencies=("$_branding_info" "$_locations_info" "$_rtd_recipies_info") # All library functions are listed below in a few sections: # - Standard Interactions # - System Management # - Software Management # - Network # - Security # - Virtual Machine Management # - Internal Configuration Repository # - Script Internal Functions ################################################################################################ # # . -------------------------------------------------------------------. # | [Esc] [F1][F2][F3][F4][F5][F6][F7][F8][F9][F0][F10][F11][F12] o o o| # | | # | [`][1][2][3][4][5][6][7][8][9][0][-][=][_<_] [I][H][U] [N][/][*][-]| # | [|-][Q][W][E][R][T][Y][U][I][O][P][{][}] | | [D][E][D] [7][8][9]|+|| # | [CAP][A][S][D][F][G][H][J][K][L][;]['][#]|_| [4][5][6]|_|| # | [^][\][Z][X][C][V][B][N][M][,][.][/] [__^__] [^] [1][2][3]| || # | [c] [a][________________________][a] [c] [<][V][>] [ 0 ][.]|_|| # `--------------------------------------------------------------------' # # # .d8888b. 888 888 888 # d88P Y88b 888 888 888 # Y88b. 888 888 888 # "Y888b. 888888 8888b. 88888b. .d88888 8888b. 888d888 .d88888 # "Y88b. 888 "88b 888 "88b d88" 888 "88b 888P" d88" 888 # "888 888 .d888888 888 888 888 888 .d888888 888 888 888 # Y88b d88P Y88b. 888 888 888 888 Y88b 888 888 888 888 Y88b 888 # "Y8888P" "Y888 "Y888888 888 888 "Y88888 "Y888888 888 "Y88888 # # # # 8888888 888 888 d8b # 888 888 888 Y8P # 888 888 888 # 888 88888b. 888888 .d88b. 888d888 8888b. .d8888b 888888 888 .d88b. 88888b. .d8888b # 888 888 "88b 888 d8P Y8b 888P" "88b d88P" 888 888 d88""88b 888 "88b 88K # 888 888 888 888 88888888 888 .d888888 888 888 888 888 888 888 888 "Y8888b. # 888 888 888 Y88b. Y8b. 888 888 888 Y88b. Y88b. 888 Y88..88P 888 888 X88 # 8888888 888 888 "Y888 "Y8888 888 "Y888888 "Y8888P "Y888 888 "Y88P" 888 888 88888P' # ################################################################################################ display_gui() { # Description: Displays a GUI dialog box with the given message. # # This function uses the 'dialog' command to display a GUI dialog box with the provided message. # The dialog box is displayed in a terminal window, and the user can interact with it. # # Globals: # - RTD_GUI # Arguments: # - "message": The message to be displayed in the dialog box. # Outputs: # - Displays a GUI dialog box with the provided message. # Returns: # - 0 on success, ESC on user cancellation. # # Usage: # display_gui "Hello, World!" # # End of Documentation dialog::check_menu_availability dialog::display_notice "$1" } dialog::check_menu_availability() { # Description: First discover what menu system is installed. Some systems use "dialog" and # other systems use whiptail for the terminal to show menus and dialogs. # If nothing is found, then make sure it is available before continuing. # # Globals: # RTD_GUI respected as default value. If unset it will be set to "dialog" or "whiptail" # depending on which is present. IF both are present, the dialog is prefferred. # # Arguments: None accepted # Outputs: Interactive # Returns: Default exit status of the last command run. # Usage: dialog::check_menu_availability # # End of documentation if hash dialog 2>/dev/null; then : "${RTD_GUI:=dialog --clear}" export RTD_GUI elif hash whiptail 2>/dev/null; then : "${RTD_GUI:="whiptail --fb"}" export RTD_GUI if ($RTD_GUI --backtitle "$BRANDING" \ --title "System Information Menu" \ --no-button "NO: Use whiptail" \ --yes-button "YES: Install dialog" \ --yesno "Please NOTE that we are using WHIPTAIL as a terminal menu system, which is missing several features compared to the default: DIALOG menu system. There are a few reasons we may be using WHIPTAIL instead: I was forced to use it or it is the only terminal menu system available... If you continue with the current WHIPTAIL some things might not work. \n \n May I please try to install the dialog system in stead? . \n " \ 20 90); then RTD_GUI=dialog term::err_no_menu_system_found else echo "User selected No, exit status was $?." fi else term::err_no_menu_system_found dialog && return 1 || exit 1 fi } dialog::display_cmd_output() { # Description: Displays the output of a command in a dialog box. # # This function takes a command as an argument and executes it. # The output of the command is then displayed in a dialog box. # This is a convenient way to display the output of a command in a terminal in a nice way. # The dialog box is displayed using the 'dialog' command, which must be installed on the system. # If the user cancels the operation, the function returns ESC. # # Globals: # - dialog # Arguments: # - ["String to execute"]: The command to be executed and its arguments. # Outputs: # - Displays the command output in a dialog box. # Returns: # - 0 on success, ESC on user cancellation. # # Usage: # dialog::display_cmd_output "apt -y upgrade" # # End of Documentation _cmd="$*" ${_cmd} | ${RTD_GUI:-dialog} --backtitle "\Zb$PUBLICATION $VERSION\ZB" --progressbox "RUNNING: ${_cmd}" 25 120 } dialog::copy_file_progress() { # Description: Displays a file copy progress dialog. # This function shows a progress bar while copying files from a source directory to a destination directory. # # Globals: # - dialog # Arguments: # - "source": The directory containing the files to be copied. # - "destination": The directory where the files will be copied to. # Outputs: # - Displays a progress dialog box showing the file copy progress. # Returns: # - 0 on success, ESC on user cancellation. # # Usage: # dialog::copy_file_progress "source" "destination" # # Example: # dialog::copy_file_progress "/path/to/source" "/path/to/destination" # # Details: # - This function takes two arguments: the source directory containing the files to be copied, # and the destination directory where the files will be copied to. # - It creates a progress bar dialog using the 'dialog' command and updates it as each file is copied. # - The progress bar shows the percentage of files copied and the name of the current file being copied. # - The function returns 0 if the copying process completes successfully, or ESC if the user cancels the operation. # # Note: The 'dialog' command must be installed for this function to work. # # End of Documentation _dirs=(${1}/*) # Destination directory _dest="${2}" [ ! -d "${_dest}" ] && mkdir -p "${_dest}" dialog --title "Copying files" --gauge "Copying file..." 10 75 < <( # Get total number of files in array n=${#_dirs[*]} i=0 for f in "${_dirs[@]}"; do # calculate progress _pct=$((100 * (++i) / n)) # update dialog box cat </dev/null done ) unset _dirs unset _dest unset _pct } dialog::copy_with_progress() { # Description: Function to display a progress bar while copying a large file to a destination. # This function uses 'dialog' to create a progress bar that shows the percentage of an ISO file being copied. # # Globals: # - None # Arguments: # - "$1": The path to the large file (ISO) file to be copied. # - "$2": The destination path where the large file (ISO) file will be copied. # - "$3": The mount point directory (used for display purposes). # Outputs: # - Displays a dialog box with the copy progress. # Returns: # - 0 on success. # # Usage: # dialog::copy_with_progress "/path/to/iso/file.iso" "/path/to/destination" "/mount/point" # # Example: # dialog::copy_with_progress "/home/user/file.iso" "/mnt/usb/file.iso" "/mnt/usb" # # Dependencies: # - dialog: To display the progress bar. # - pv: To monitor the progress of the file copy. # - mktemp: To create a temporary named pipe. # # Notes: # - Ensure 'dialog' and 'pv' are installed on your system for this function to work correctly. # # End of Documentation local iso_file="$1" local destination="$2" local mount_point="$3" local gauge_pid local rc=0 # Ensure required tools are available if ! software::check_native_package_dependency dialog; then return 1 fi if ! software::check_native_package_dependency pv; then return 1 fi # Get the size of the ISO file local iso_size iso_size=$(stat -c%s "$iso_file") || return 1 # Create a named pipe for progress updates local pipe=$(mktemp -u) mkfifo "$pipe" || return 1 # Start dialog progress bar dialog --title "Copying ISO" --gauge "Copying $(basename "$iso_file") to $destination" 10 70 0 <"$pipe" & gauge_pid=$! # Copy the file and update progress if ! pv -n -s "$iso_size" "$iso_file" >"$destination" 2>"$pipe"; then rc=$? fi # Clean up rm "$pipe" wait "$gauge_pid" 2>/dev/null || true return $rc } dialog::display_notice() { # Description: Displays an information notice using a dialog box. # This function provides a convenient way to display a message to an end user in a terminal. # # Globals: # - "${RTD_GUI}" (optional): Specifies the command to use for displaying the dialog (defaults to 'dialog'). # - "${PUBLICATION}" (optional): Sets the backtitle of the dialog box. # Arguments: # - "$1": The message string to be displayed in the dialog box. # Outputs: # - Displays the specified message in a dialog box. # Returns: # - 0 on success, ESC on user cancellation. # # Usage: # dialog::display_notice "The message that you want to display" # # Dependencies: # - dialog: To display the message in a dialog box. # # Notes: # - Ensure 'dialog' is installed on your system for this function to work correctly. # # End of Documentation system::log_item "checking for dialog..." if ! hash "${RTD_GUI:-dialog}" &>/dev/null; then system::log_item "${RTD_GUI:-dialog} not found..." software::check_native_package_dependency "${RTD_GUI:-dialog}" &>/dev/null || return 1 else system::log_item "${RTD_GUI:-dialog} found..." fi system::log_item "Notice: ${*}" dialog --backtitle "${PUBLICATION:-"Notice"}" --colors --no-collapse --title "Notice" --msgbox "\n ${*} \n" 15 78 clear return 0 } dialog::display_error() { # Description: Displays an error notice using a dialog box. # This function provides a convenient way to display an error message to an end user in a terminal. # # Globals: # - "${RTD_GUI}" (optional): Specifies the command to use for displaying the dialog (defaults to 'dialog'). # - "${PUBLICATION}" (optional): Sets the backtitle of the dialog box. # Arguments: # - "$1": The error message string to be displayed in the dialog box. # Outputs: # - Displays the specified error message in a dialog box. # Returns: # - 0 on success, ESC on user cancellation. # # Usage: # dialog::display_error "The message that you want to display" # # Dependencies: # - dialog: To display the error message in a dialog box. # # Notes: # - Ensure 'dialog' is installed on your system for this function to work correctly. # # End of Documentation system::log_item "checking for dialog..." if ! hash "${RTD_GUI:-dialog}" &>/dev/null; then system::log_item "${RTD_GUI:-dialog} not found..." software::check_native_package_dependency "${RTD_GUI:-dialog}" &>/dev/null || return 1 else system::log_item "${RTD_GUI:-dialog} found..." fi system::log_item "Notice: ${*}" dialog --backtitle "${PUBLICATION:-"ERROR"}" --colors --no-collapse --title "ERROR" --msgbox "\n ${*} \n" 15 78 clear return 0 } dialog::display_summary_message() { # Description: Function to read a variable "result" and display its contents. The purpose of this function # is simply to make it easy and convenient to display a message to an end user in a terminal # in a nice way. To use this function, simply call it after populating the variable result. # # Globals: ${result}, ${BRANDING} # # Arguments: ["Title to display"] # # Outputs: Message in dialog box # # Returns: 0 or ESC # # Usage: # # result=$( command with output) # dialog::display_result "title of the message" # # End of Documentation if ! hash dialog &>/dev/null; then system::log_item "dialog not found..." software::check_native_package_dependency dialog &>/dev/null || return 1 else system::log_item "dialog found..." fi system::log_item "Displaying summary message TITLE: $1 and the message: ${_summary_message}" if echo "${FUNCNAME[1]}" | grep "make_kvm_virtual_machine"; then dialog --backtitle "$BRANDING" --colors --no-collapse --title "$1" --msgbox "\n ${_summary_message} \n" 0 0 else dialog --backtitle "$BRANDING" --colors --no-collapse --title "$1" --msgbox "${_summary_message}" "${HEIGHT:-"20"}" "${WIDTH:-"80"}" fi clear return 0 } dialog::display_result() { # Description: Displays the contents of the variable "result" in a message box. # This function makes it easy and convenient to display a message to an end user in a terminal. # It checks for the availability of the dialog utility and uses it to display a message box. # # Globals: # - ${result}: The variable whose contents will be displayed. # - ${BRANDING} (optional): Sets the backtitle of the dialog box. # Arguments: # - "$1": The title of the message box. # Outputs: # - Displays the content of the "result" variable in a dialog box. # Returns: # - 0 on success, ESC on user cancellation. # # Usage: # result=$(command_with_output) # dialog::display_result "Title of the message" # # Example: # result=$(ls -l) # dialog::display_result "Directory Listing" # # Dependencies: # - dialog: To display the message box. # # Notes: # - If the dialog utility is not found, the function checks for dependencies and returns 1 if they are not met. # - The backtitle, colors, collapse, height, and width of the message box are customizable using environment variables. # # End of Documentation system::log_item "checking for dialog..." if ! hash "${RTD_GUI:-dialog}" &>/dev/null; then system::log_item "${RTD_GUI:-dialog} not found..." software::check_native_package_dependency "${RTD_GUI:-dialog}" &>/dev/null || return 1 else system::log_item "${RTD_GUI:-dialog} found..." fi system::log_item "Displaying result: $1 " ${RTD_GUI:-dialog} --backtitle "$BRANDING" --colors --no-collapse --title "$1" --msgbox "$result" "${HEIGHT:-"20"}" "${WIDTH:-"80"}" clear } dialog::prompt_yes_no() { # Description: Displays a Yes/No prompt using a dialog box. # This function provides a convenient way to ask the user a Yes/No question in a terminal, # with customizable backtitle, title, and message. If only one argument is passed, it will # treat it as the message. Otherwise, it will intelligently parse --back-title, --title, and # --message flags to determine what to display. # # Globals: # - "${RTD_GUI}" (optional): Specifies the command to use for displaying the dialog (defaults to 'dialog'). # - "${PUBLICATION}" (optional): Sets the default backtitle of the dialog box. # Arguments: # - "--back-title": (Optional) The backtitle of the dialog box. # - "--title": (Optional) The title of the dialog box. # - "--message": (Optional) The message string (query) to be displayed in the dialog box. # - If a single argument is provided without flags, it is treated as the message. # Outputs: # - Displays a Yes/No prompt to the user. # Returns: # - 0 if the user selects Yes. # - 1 if the user selects No. # - ESC on user cancellation. # # Usage: # dialog::prompt_yes_no --back-title "System Check" --title "Restart Confirmation" --message "Do you want to restart?" # dialog::prompt_yes_no "Do you want to proceed?" # # Dependencies: # - dialog: To display the prompt in a dialog box. # # Notes: # - 'dialog' will be installed on your system if required for this function to work correctly. # # End of Documentation # Initialize default values local backtitle="${PUBLICATION:-"Query"}" local title="Confirmation" local message="Are you sure you want to proceed?" # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in --back-title) backtitle="$2" shift 2 ;; --title) title="$2" shift 2 ;; --message) message="$2" shift 2 ;; *) # If only a single unflagged argument is passed, treat it as the message message="$1" shift ;; esac done system::log_item "Checking for dialog..." if ! hash "${RTD_GUI:-dialog}" &>/dev/null; then system::log_item "${RTD_GUI:-dialog} not found..." software::check_native_package_dependency "${RTD_GUI:-dialog}" &>/dev/null || return 1 else system::log_item "${RTD_GUI:-dialog} found..." fi system::log_item "Displaying Yes/No prompt: $message" # Display the Yes/No dialog "${RTD_GUI:-dialog}" --backtitle "$backtitle" --title "$title" --yesno "\n$message\n" 10 50 # Capture the exit status local exit_status=$? system::log_item "Exit status: $exit_status" clear return $exit_status } yad::display_cmd_output() { # Description: Displays the output of a command in a YAD box. # This function takes a command as an argument, executes it, and displays the output in a YAD box. # # Globals: # - yad # Arguments: # - "$@": The command to be executed and its arguments. # Outputs: # - Displays the command output in a YAD box. # Returns: # - 0 on success or if the YAD box is closed with the "Close" button. # - "ESC" if the YAD box is closed with the "ESC" key. # # Usage: # yad::display_cmd_output "command_to_execute" # # Example: # yad::display_cmd_output "apt -y upgrade" # # Dependencies: # - yad: To display the command output in a YAD box. # # Notes: # - If the YAD utility is not found, the function checks for dependencies and returns 1 if they are not met. # # End of Documentation # Command to execute local cmd=$@ system::log_item "checking for diayadog..." if ! hash "yad" &>/dev/null; then system::log_item "yad not found..." software::check_native_package_dependency "yad" &>/dev/null || return 1 else system::log_item "yad found..." fi # Execute the command and pipe its output to yad ( # Ensure any error messages are sent to standard output so yad can display them exec 2>&1 # Execute the command echo "Executing: $cmd" $cmd echo "Command completed. You can close this window." ) | yad --text-info --width=700 --height=400 --title "Command Output" } yad::display_progressbar_pulsating() { # Description: Displays the output of a command in a pulsating progress box. # This function takes a command as an argument, executes it, and displays the output in a progress box using the 'yad' command. # # Globals: # - yad # Arguments: # - "$*": The command to be executed and its arguments. # Outputs: # - Displays the command output in a YAD progress box. # Returns: # - 0 on success or if the YAD box is closed with the "Close" button. # - "ESC" if the YAD box is closed with the "ESC" key. # # Usage: # yad::display_progressbar_pulsating "command_to_execute" # # Example: # yad::display_progressbar_pulsating "apt -y upgrade" # # Dependencies: # - yad: To display the command output in a YAD progress box. # # Notes: # - The progress box shows a pulsating animation and automatically closes when the command execution is complete. # - If the YAD utility is not found, the function checks for dependencies and returns 1 if they are not met. # # End of Documentation _cmd="$*" system::log_item "checking for yad..." if ! hash "yad" &>/dev/null; then system::log_item "yad not found..." software::check_native_package_dependency "yad" &>/dev/null || return 1 else system::log_item "yad found..." fi ${_cmd} | yad --title="$PUBLICATION $VERSION" --progress --pulsate --auto-close --auto-kill --text="RUNNING: ${_cmd}" --width=300 --height=100 } zenity::display_info() { # Description: Displays an information notice using a Zenity info box. # This function provides a convenient way to display a message to an end user in a GUI. # # Globals: # - $_TITLE (optional): Sets the title of the Zenity info box. # - $selection (optional): Additional text to include in the title. # Arguments: # - "$*": The message string to be displayed in the Zenity info box. # Outputs: # - Displays the specified message in a Zenity info box. # Returns: # - None # # Usage: # zenity::display_info "The message that you want to display" # # Example: # zenity::display_info "This is an important notice for the user." # # Dependencies: # - zenity: To display the message in a Zenity info box. # # Notes: # - If the Zenity utility is not found, the function checks for dependencies and returns 1 if they are not met. # - The info box is customizable using the global variables $_TITLE and $selection. # # End of Documentation _text="${*}" hash zenity &>/dev/null || software::check_native_package_dependency zenity &>/dev/null || return 1 zenity --info --text --title="${_TITLE:="Notice"}: $selection" --text="$_text" --ellipsize --height=600 --width=800 2>/dev/null } yad::display_info() { # Description: Displays an information notice using a Zenity info box. # This function provides a convenient way to display a message to an end user in a GUI. # # Globals: # - $_TITLE (optional): Sets the title of the Zenity info box. # - $selection (optional): Additional text to include in the title. # Arguments: # - "$*": The message string to be displayed in the Zenity info box. # Outputs: # - Displays the specified message in a Zenity info box. # Returns: # - None # # Usage: # zenity::display_info "The message that you want to display" # # Example: # zenity::display_info "This is an important notice for the user." # # Dependencies: # - zenity: To display the message in a Zenity info box. # # Notes: # - If the Zenity utility is not found, the function checks for dependencies and returns 1 if they are not met. # - The info box is customizable using the global variables $_TITLE and $selection. # # End of Documentation _text="${*}" hash yad &>/dev/null || software::check_native_package_dependency yad &>/dev/null || return 1 yad --info --text --title="${_TITLE:="Notice"}: $selection" --text="$_text" --ellipsize --height=600 --width=800 2>/dev/null } zenity::display_url() { # Description: Displays the content of a URL in a GUI using Zenity. # This function makes it easy and convenient to display web content to an end user in a nice way. # To use this function, simply call it passing the URL as an argument. # # Globals: # $_TITLE (optional): Sets the title of the Zenity window. # Arguments: # ["URL"]: The URL whose content will be displayed. # Outputs: # - Formatted HTML message in a Zenity window. # Returns: # - None # # Usage: # zenity::display_url "https://www.someplace.com/index.html" # # Example: # zenity::display_url "https://www.example.com" # # Dependencies: # - zenity: To display the URL content in a Zenity window. # # Notes: # - If the Zenity utility is not found, the function checks for dependencies and returns 1 if they are not met. # # End of Documentation local _url="${*}" hash zenity &>/dev/null || software::check_native_package_dependency zenity &>/dev/null || return 1 hash wget &>/dev/null || software::check_native_package_dependency wget &>/dev/null || return 1 local tmp_folder=$(mktemp -d) wget -q "${_url}" -O "${tmp_folder}/file.md" &>/dev/null yad::display_file "${tmp_folder}/file.md" #&>/dev/null } yad::display_url() { # Description: Displays the content of a URL in a GUI using Zenity. # This function makes it easy and convenient to display web content to an end user in a nice way. # To use this function, simply call it passing the URL as an argument. # # Globals: # $_TITLE (optional): Sets the title of the Zenity window. # Arguments: # ["URL"]: The URL whose content will be displayed. # Outputs: # - Formatted HTML message in a Zenity window. # Returns: # - None # # Usage: # zenity::display_url "https://www.someplace.com/index.html" # # Example: # zenity::display_url "https://www.example.com" # # Dependencies: # - zenity: To display the URL content in a Zenity window. # # Notes: # - If the Zenity utility is not found, the function checks for dependencies and returns 1 if they are not met. # # End of Documentation local _url="${*}" hash yad &>/dev/null || software::check_native_package_dependency yad &>/dev/null || return 1 hash wget &>/dev/null || software::check_native_package_dependency wget &>/dev/null || return 1 local tmp_folder=$(mktemp -d) wget -q "${_url}" -O "${tmp_folder}/yad.md" &>/dev/null yad::display_file "${tmp_folder}/yad.md" #&>/dev/null unset _url } zenity::display_file() { # Description: Displays the content of a text file in a Zenity window. # This function makes it easy and convenient to display text content to an end user in a GUI. # To use this function, simply call it passing the file path as an argument. # # Globals: # $_TITLE (optional): Sets the title of the Zenity window. # Arguments: # ["/path/to/file.txt"]: The path to the text file to be displayed. # Outputs: # - Displays the content of the specified text file in a Zenity window. # Returns: # - None # # Usage: # zenity::display_file "/path/to/file.txt" # # Example: # zenity::display_file "/path/to/file.txt" # # Dependencies: # - zenity: To display the text file content in a Zenity window. # # Notes: # - If the Zenity utility is not found, the function checks for dependencies and returns 1 if they are not met. # # End of Documentation _filename="${*}" hash zenity &>/dev/null || software::check_native_package_dependency zenity &>/dev/null || return 1 hash pandoc &>/dev/null || software::check_native_package_dependency pandoc &>/dev/null || return 1 zenity --text-info --title="${_TITLE:="$_filename"}:" --filename=<(pandoc -s $_filename -t plain) --width=800 --height=600 2>/dev/null #&>/dev/null } yad::display_file() { # Description: Displays the content of a text file in a Zenity window. # This function makes it easy and convenient to display text content to an end user in a GUI. # To use this function, simply call it passing the file path as an argument. # # Globals: # $_TITLE (optional): Sets the title of the Zenity window. # Arguments: # ["/path/to/file.txt"]: The path to the text file to be displayed. # Outputs: # - Displays the content of the specified text file in a Zenity window. # Returns: # - None # # Usage: # zenity::display_file "/path/to/file.txt" # # Example: # zenity::display_file "/path/to/file.txt" # # Dependencies: # - zenity: To display the text file content in a Zenity window. # # Notes: # - If the Zenity utility is not found, the function checks for dependencies and returns 1 if they are not met. # # End of Documentation _filename="${*}" hash yad &>/dev/null || software::check_native_package_dependency yad &>/dev/null || return 1 hash pandoc &>/dev/null || software::check_native_package_dependency pandoc &>/dev/null || return 1 yad --text-info --title="${_TITLE:="$_filename"}:" --filename=<(pandoc -s $_filename -t plain) --wrap --width=800 --height=600 &>/dev/null } term::animate_while_command() { # Description: Displays an animation during the execution of a silent command. # This function is useful for running another function or command that may take some time to complete. # Note that this works best if the function or command does not print to the terminal. # # Globals: # - None # Arguments: # - "$@": The command or function to be executed. # Outputs: # - Standard output (suppressed) # Returns: # - 0 on success, 1 if no command is specified. # # Usage: # term::animate_while_command "command_or_function" # # Example: # term::animate_while_command "sleep 10" # # Dependencies: # - term::start_animation: To start the animation. # - term::stop_animation: To stop the animation. # # Notes: # - Ensure that the command or function passed as an argument does not produce output to the terminal for best results. # # End of Documentation if [[ -z ${1} ]]; then write_error "Specifying a command to wait for is required!" return 1 fi local logfile="${TERM_TASK_LOGFILE:-/dev/null}" local monitor_was_enabled=0 if [[ -o monitor ]]; then monitor_was_enabled=1 set +o monitor fi term::start_animation "$@" # Run the command and log output while the animation updates in the background. "${@}" >>"$logfile" 2>&1 RET_CODE=$? term::stop_animation "$RET_CODE" if (( monitor_was_enabled )); then set -o monitor fi return "$RET_CODE" } term::start_animation() { # Description: # A simple function to display and animation during a silent acton # # Globals: # Arguments: # Outputs: Standard out # Returns: # Usage: # term::start_animation "Display text" # term::stop_animation # # End of documentation local cmd_while if [[ -n ${TERM_TASK_CMD_DISPLAY:-} ]]; then cmd_while="${TERM_TASK_CMD_DISPLAY}" else printf -v cmd_while '%q ' "$@" cmd_while=${cmd_while% } cmd_while="Executing ${cmd_while}" fi if [[ -z ${cmd_while} ]]; then write_error "Specifying a command to wait for is required!" return 1 fi # make some decent display terminal graphics... setterm -cursor off export ANIM_PID="0" local PAD="${green}---------------------------------------------------------" LINE="$(printf "%s %s" "${magenta}${cmd_while}" " $PAD" | cut -c 1-${#PAD}) : " anim=( "${LINE} ${blue}•${green}•${red}•${magenta}• ${ENDCOLOR}" "${LINE} ${green}•${red}•${magenta}•${blue}• ${ENDCOLOR}" "${LINE} ${red}•${magenta}•${blue}•${green}• ${ENDCOLOR}" "${LINE} ${magenta}•${blue}•${green}•${red}• ${ENDCOLOR}" "${LINE} ${blue}•${green}•${red}•${magenta}•${ENDCOLOR}" ) ( while true; do for i in {0..4}; do printf "\r\033[2K ${anim[i]}" sleep 0.1 done for i in {4..0}; do printf "\r\033[2K ${anim[i]}" sleep 0.1 done done ) & export ANIM_PID="${!}" } term::stop_animation() { # Description: # A simple function to STOP display and animation during a silent acton # # Globals: # Arguments: # Outputs: Standard out # Returns: # Usage: # term::stop_animation # # End of documentation if [[ -n "$ANIM_PID" ]] && kill -0 "$ANIM_PID" 2>/dev/null; then kill "$ANIM_PID" wait "$ANIM_PID" 2>/dev/null fi if [[ $RET_CODE == 0 ]]; then printf "\r\033[2K ${LINE} [ \xE2\x9C\x94 ] ${GREEN} OK! ${ENDCOLOR} \n" else printf "\r\033[2K ${LINE} [ ! ] ${RED} FAILED! ${ENDCOLOR} \n" fi unset LINE setterm -cursor on 2>/dev/null } term::task_exec_list_output() { # DESCRIPTION: # Executes a given command while displaying a formatted status line # in the terminal and logging output to the current log file ($_LOGFILE). # Provides visual feedback with terminal graphics to indicate success or failure. # # Intended to be used for clear visual execution tracking in scripts. # # USAGE: # term::task_exec_list_output [args...] # # PARAMETERS: # $@ - The full command to execute (can include arguments). # # OUTPUTS: # - Prints a truncated command summary with an "Executing ..." message. # - Shows a success checkmark (✔ OK) in green or a failure mark (FAILED) in red. # - Appends full command output (stdout and stderr) to $_LOGFILE. # # LOGGING: # - Logs the function call and parameters via system::log_item. # # EXAMPLE: # term::task_exec_list_output ls -lh /tmp # # DEPENDENCIES: # - system::log_item # - Global vars: $_LOGFILE, $GREEN, $RED, $ENDCOLOR # # RETURNS: # - Returns the exit status of the executed command. # # NOTE: # End of documentation local logfile cmd_display status if ! logfile=$(system::determine_logfile); then return 1 fi system::log_item "Running ${FUNCNAME[0]} requested by ${FUNCNAME[1]} with parameters $*" printf -v cmd_display '%q ' "$@" cmd_display=${cmd_display% } TERM_TASK_LOGFILE="$logfile" TERM_TASK_CMD_DISPLAY="Executing ${cmd_display}" term::animate_while_command "$@" status=$? unset TERM_TASK_LOGFILE TERM_TASK_CMD_DISPLAY return "$status" } term::err_no_menu_system_found() { # Description: Function to handle the error condition if a manu system is not found on the system. # On occasion it may be neede to display dialog boxes and selection menus even in a terminal. # for these cases; dialog, whiptail (newt), or zenity may be needed. # This function will attempt to install the desired menu system and if it cannot or the user # opts out it will error and exit the script. # # Globals: RTD_GUI # Arguments: None # Outputs: Interactive # Returns: default exit status of the last command run. # Usage: # term::err_no_menu_system_found # End of documentation write_error " ______________________________________________________________________ \n There is eiter no way to display menus on this system or you have told me \n to install the default menu system! \n This is required to display the administrative menus... \n \n ¯\_( ͡👁️ ͜ʖ ͡👁️)_/¯ \n ______________________________________________________________________ \n" write_warning "May I attepmpt to install this ability to your system? \a " read -p "Add software: (y/n)?" choice case "$choice" in y | Y) : "${RTD_GUI:=$1}" for i in dnf yum zypper apt-get; do if hash $i 2>/dev/null; then $i install $RTD_GUI -y if $? eq 0; then echo -e $YELLOW"$RTD_GUI installed... exporting..." RTD_GUI="dialog --clear" export RTD_GUI return 0 fi fi done ;; n | N) err_no_menu_system_available ;; *) read -p "Invalid Selection" && term::err_no_menu_system_found || exit 1 ;; esac } ################################################################################################ # # # +-----+ +-----+ +-----+ # |Edge1| |Edge2| |Edge3| # +--+--+ +--+--+ +--+--+ # | | | # | +--+--+ | # +-------+BGP1 +-------+ # +--+--+ # | # +--+--+ # |VMH1 | # +-----+ # ################################################################################################ # # ██    ██ ████████ ████████ ██      ██  ███████  ████████  ██    ██  # ███   ██ ██          ██    ██  ██  ██ ██     ██ ██     ██ ██   ██   # ████  ██ ██          ██    ██  ██  ██ ██     ██ ██     ██ ██  ██    # ██ ██ ██ ██████      ██    ██  ██  ██ ██     ██ ████████  █████     # ██  ████ ██          ██    ██  ██  ██ ██     ██ ██   ██   ██  ██    # ██   ███ ██          ██    ██  ██  ██ ██     ██ ██    ██  ██   ██   # ██    ██ ████████    ██     ███  ███   ███████  ██     ██ ██    ██  # ################################################################################################ network::check_inet_access() { # Description: # Verifies internet connectivity by pinging known public IPs. # Supports an optional wait prompt in interactive mode if connectivity is unavailable. # # Globals: # _OEM_TEST_IPS - Optional space-separated list of IPs to ping. Defaults to 8.8.8.8, 1.1.1.1, 9.9.9.9. # # Arguments: # [--interactive] [WAIT_SECONDS] # --interactive Enables interactive prompt if internet is not available. # WAIT_SECONDS Optional: Time to wait before continuing. Default is 10 seconds. # # Outputs: # STDOUT: Status messages about internet connectivity. # # Returns: # 0 if internet access is available # 1 if no internet access is detected # # Usage: # network::check_inet_access # network::check_inet_access --interactive # network::check_inet_access --interactive 60 # # Notes: # If --interactive is used without a second argument, it waits indefinitely for user input. # If a timeout is provided, it waits the specified number of seconds then continues. # The function will return 0 if internet access is available, otherwise it returns 1. # # End of Documentation local wait_time local -a test_ips mapfile -t test_ips < <(network::get_oem_test_ips) case "$1" in --interactive) wait_time="$2" for ip in "${test_ips[@]}"; do if ping -c 1 "$ip" &>/dev/null; then write_status "✅ Internet access is available." return 0 else write_error "❌ No internet access detected." if [[ -n "$wait_time" ]]; then read -t "$wait_time" -p "NOTICE! No internet access. Press [ENTER] to continue or [CTRL+C] to abort. Continuing in $wait_time seconds... " else read -p "NOTICE! No internet access. Press [ENTER] to continue or [CTRL+C] to abort. " fi return 1 fi done ;; *) local default_ip="${test_ips[0]:-8.8.8.8}" if ping -c 1 "$default_ip" &>/dev/null; then system::log_item "✅ Internet access is available." return 0 else system::log_item "❌ No internet access detected." return 1 fi ;; esac } network::get_oem_test_ips() { # Description: Return test IPs as newline-separated list honoring _OEM_TEST_IPS override. # Arguments: None. # Outputs: STDOUT newline-delimited IPs. # Returns: 0 # End of documentation if [[ -n "${_OEM_TEST_IPS}" ]]; then # shellcheck disable=SC2206 local ips=(${_OEM_TEST_IPS}) printf "%s\n" "${ips[@]}" else printf "%s\n" "8.8.8.8" "1.1.1.1" "9.9.9.9" fi } network::whats_my_ipinfo() { # Description: # Attempts to retrieve public IP and geolocation data using multiple external services. # Automatically installs curl if missing. Supports optional timeout for error prompt. # # Globals: # None # # Arguments: # --timeout Optional: timeout in seconds to wait on failure prompt. # # Outputs: # STDOUT: IP and geolocation info from the first responsive service. # # Returns: # 0 if geolocation data was retrieved successfully # 1 if all services failed or curl is missing/unavailable # # Usage: # network::whats_my_ipinfo # network::whats_my_ipinfo --timeout 10 # # Example: # - Get IP info and print to console immediatley: # network::whats_my_ipinfo # # - Get IP info and display in a dialog box: # dialog::display_result "IP Info" "$(network::whats_my_ipinfo)" # # - Get IP info and store in a variable and print to console later: # result=$(network::whats_my_ipinfo) # printf "%s\n" "$result" # # - Get IP info with a timeout of 5 seconds # network::whats_my_ipinfo --timeout 5 # # Notes: # - The function will try multiple services in order until one succeeds. # - If curl is not installed, it will attempt to install it using software::add_native_package. # - If all services fail, it will prompt the user to continue or abort. # - The timeout option allows the user to specify a wait time before continuing. # - The function will return 0 if successful, otherwise it returns 1. # # End of Documentation local timeout service url response local -a ipinfo_services=( "https://ipinfo.io" "https://ifconfig.co/json" "https://api.myip.com" "https://ipapi.co/json" "https://ipwho.is" ) if [[ "$1" == "--timeout" && -n "$2" ]]; then timeout="$2" fi if ! command -v curl >/dev/null 2>&1; then system::log_item "🚫 curl not found, attempting to install..." if ! software::add_native_package curl; then system::log_item "❌ Failed to install curl. Please install it manually." return 1 fi clear fi for url in "${ipinfo_services[@]}"; do system::log_item "🌐 Trying geolocation service: $url" if response=$(curl -s --connect-timeout 5 "$url") && [[ -n "$response" ]]; then system::log_item "✅ Retrieved IP and geolocation data from $url" printf '%s\n' "$response" return 0 else system::log_item "⚠️ Failed to retrieve data from $url" fi done system::log_item "❌ All geolocation services failed." if [[ -n "$timeout" ]]; then read -t "$timeout" -p $"NOTICE! No internet access.\nThis script may require internet to function properly.\nPress [ENTER] to continue or [CTRL+C] to abort. Continuing in $timeout seconds...\n" else read -p $'\nNOTICE! No internet access.\nThis script may require internet to function properly.\nPress [ENTER] to continue or [CTRL+C] to abort.\n' fi return 1 } network::whats_my_external_ip() { # Description: # Retrieves the system's external IP address using multiple fallback services. # Automatically installs curl if missing (via software::add_native_package). # # Globals: # None # # Arguments: # None # # Outputs: # STDOUT: External IP address # STDERR: Error messages and status logs via system::log_item # # Returns: # 0 if external IP was retrieved successfully # 1 if curl could not be installed or all lookups failed # # Usage: # network::whats_my_external_ip # # Example: # ip=$(network::whats_my_external_ip) local _my_ip="unknown" local url local -a fallback_urls=( "https://myip.dnsomatic.com" "https://ipinfo.io/ip" "https://api.ipify.org" "https://checkip.amazonaws.com" "https://icanhazip.com" "https://ifconfig.co" "https://api64.ipify.org" "https://myexternalip.com/raw" ) if ! command -v curl >/dev/null 2>&1; then system::log_item "🚫 curl not found, attempting to install..." if ! software::add_native_package curl; then system::log_item "❌ Failed to install curl. Please install it manually." return 1 fi system::log_item "✅ curl installed successfully." fi system::log_item "🌐 Attempting to retrieve external IP address..." for url in "${fallback_urls[@]}"; do if _my_ip=$(curl -s --connect-timeout 5 "$url"); then if [[ "$_my_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then system::log_item "✅ External IP address retrieved from $url: $_my_ip" printf '%s\n' "$_my_ip" return 0 fi fi done system::log_item "❌ All IP services failed to provide a valid external IP address." return 1 } network::rsync_upload() { # Description: # Transfer files or directories to a remote host using rsync over SSH, # showing a live progress bar with dialog unless --gui false is given. # # Usage: # dialog::rsync_upload --source /path --destination /remote/path --user USER --host HOST [--exclude '*.git'] [--gui false] # # Example: # # # Returns: # 0 on success, 1 on failure # # Globals: # - None # # End of Documentation local src= dest= ssh_user= ssh_host= gui="true" exclude_opt= while [[ $# -gt 0 ]]; do case "$1" in --source) src="$2"; shift 2 ;; --destination) dest="$2"; shift 2 ;; --user) ssh_user="$2"; shift 2 ;; --host) ssh_host="$2"; shift 2 ;; --exclude) exclude_opt="--exclude=$2"; shift 2 ;; --gui) gui="$2"; shift 2 ;; *) printf "⛔ Unknown option: %s\n" "$1" >&2 return 1 ;; esac done if [[ -z "$src" || -z "$dest" || -z "$ssh_user" || -z "$ssh_host" ]]; then [[ "$gui" == "true" && -x "$(command -v dialog)" ]] && dialog::display_error "⛔ ERROR: Missing required arguments." \ || write_error "⛔ ERROR: Missing required arguments.\n" return 1 fi if [[ "$gui" != "false" ]] && ! dependency::command_exists dialog; then gui="false" fi if ! dependency::command_exists rsync find; then [[ "$gui" == "true" ]] && dialog::display_error "⛔ ERROR: Required dependencies missing: rsync or find, and could not be installed" \ || write_error "⛔ ERROR: Required dependencies missing, and could not be installed" return 1 fi if ! ssh::ensure_key_installed_on_remote "$ssh_user" "$ssh_host" ; then [[ "$gui" == "true" ]] && dialog::display_error "⛔ ERROR: The ssh keys are not installed on the remote host. This is required for security purposes" \ || write_error "⛔ ERROR: The ssh keys are not installed on the remote host. This is required for security purposes" return 1 fi if [[ ! -e "$src" ]]; then [[ "$gui" == "true" ]] && dialog::display_error "⛔ ERROR: Source path does not exist: $src" \ || write_error "⛔ ERROR: Source path does not exist: $src\n" return 1 fi if [[ "$gui" == "false" ]]; then rsync -a --info=progress2 --ignore-times $exclude_opt "$src" "${ssh_user}@${ssh_host}:${dest}" if [[ $? -ne 0 ]]; then write_error "⛔ ERROR: rsync command failed." return 1 fi return 0 fi local progress_file; progress_file=$(mktemp) local error_file; error_file=$(mktemp) local count=0 total_files=0 percent=0 if ! total_files=$(find "$src" -type f | wc -l); then dialog::display_error "⛔ ERROR: Could not count files in: $src" return 1 fi if [[ "$total_files" -eq 0 ]]; then dialog::display_error "⛔ ERROR: No files to transfer from: $src" return 1 fi { echo 0 rsync -a --info=NAME --no-inc-recursive --ignore-times $exclude_opt "$src" "${ssh_user}@${ssh_host}:${dest}" 2>>"$error_file" | \ while IFS= read -r line; do [[ "$line" =~ ^skipping ]] && continue ((count++)) percent=$((count * 100 / total_files)) printf "XXX\n%d\nProcessing: %s\nXXX\n" "$percent" "$line" done echo 100 } | dialog --title "📤 Uploading Files to ${ssh_user}@${ssh_host}..." --gauge "Transferring to ${ssh_user}@${ssh_host}..." 10 80 0 if [[ -s "$error_file" ]]; then dialog::display_error "⛔ rsync failed:\n$(tail -n 10 "$error_file")" rm -f "$progress_file" "$error_file" return 1 fi rm -f "$progress_file" "$error_file" dialog::display_notice "✅ Transfer completed successfully." return 0 } network::rsync_download() { # Description: # Download files or directories from a remote host using rsync over SSH, # showing a live progress bar with dialog unless --gui false is given. # # Usage: # dialog::rsync_download --source /remote/path --destination /local/path --user USER --host HOST [--exclude '*.git'] [--gui false] # # Returns: # 0 on success, 1 on failure # # Globals: # - None # # Example: # dialog::rsync_download --source /opt/tla --destination /home/user/tla --user bob --host server.mycompany.com --exclude '*.git' # # End of Documentation local src= dest= ssh_user= ssh_host= gui="true" exclude_opt= while [[ $# -gt 0 ]]; do case "$1" in --source) src="$2"; shift 2 ;; --destination) dest="$2"; shift 2 ;; --user) ssh_user="$2"; shift 2 ;; --host) ssh_host="$2"; shift 2 ;; --exclude) exclude_opt="--exclude=$2"; shift 2 ;; --gui) gui="$2"; shift 2 ;; *) printf "⛔ Unknown option: %s\n" "$1" >&2 return 1 ;; esac done if [[ -z "$src" || -z "$dest" || -z "$ssh_user" || -z "$ssh_host" ]]; then [[ "$gui" == "true" && -x "$(command -v dialog)" ]] && dialog::display_error "⛔ ERROR: Missing required arguments." \ || write_error "⛔ ERROR: Missing required arguments.\n" return 1 fi if [[ "$gui" != "false" ]] && ! dependency::command_exists dialog; then gui="false" fi if ! dependency::command_exists rsync find; then [[ "$gui" == "true" ]] && dialog::display_error "⛔ ERROR: Required dependencies missing: rsync or find, and could not be installed" \ || write_error "⛔ ERROR: Required dependencies missing, and could not be installed" return 1 fi if [[ "$gui" == "false" ]]; then rsync -a --info=progress2 --ignore-times $exclude_opt "${ssh_user}@${ssh_host}:${src}" "$dest" if [[ $? -ne 0 ]]; then write_error "⛔ ERROR: rsync command failed." return 1 fi return 0 fi local progress_file; progress_file=$(mktemp) local error_file; error_file=$(mktemp) local count=0 total_files=0 percent=0 if ! total_files=$(ssh "${ssh_user}@${ssh_host}" "find '$src' -type f 2>/dev/null" | wc -l); then dialog::display_error "⛔ ERROR: Could not count files in remote path: $src" return 1 fi if [[ "$total_files" -eq 0 ]]; then dialog::display_error "⛔ ERROR: No files to transfer from remote: $src" return 1 fi { echo 0 rsync -a --info=NAME --no-inc-recursive --ignore-times $exclude_opt "${ssh_user}@${ssh_host}:${src}" "$dest" 2>>"$error_file" | \ while IFS= read -r line; do [[ "$line" =~ ^skipping ]] && continue ((count++)) percent=$((count * 100 / total_files)) printf "XXX\n%d\nProcessing: %s\nXXX\n" "$percent" "$line" done echo 100 } | dialog --title "📥 Downloading Files from ${ssh_user}@${ssh_host}..." --gauge "Transferring from ${ssh_user}@${ssh_host}..." 10 80 0 if [[ -s "$error_file" ]]; then dialog::display_error "⛔ rsync failed:\n$(tail -n 10 "$error_file")" rm -f "$progress_file" "$error_file" return 1 fi rm -f "$progress_file" "$error_file" dialog::display_notice "✅ Download completed successfully." return 0 } ################################################################################################ # ________________________________________________ # / \ # | _________________________________________ | # | | | | # | | user@host:\> _ | | # | | | | # | | | | # | | | | # | | | | # | | | | # | | | | # | | | | # | | | | # | | | | # | | | | # | | | | # | |_________________________________________| | # | | # \_________________________________________________/ # \___________________________________/ # ___________________________________________ # _-' .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. --- `-_ # _-'.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.--. .-.-.`-_ # _-'.-.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-`__`. .-.-.-.`-_ # _-'.-.-.-.-. .-----.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-----. .-.-.-.-.`-_ # _-'.-.-.-.-.-. .---.-. .-------------------------. .-.---. .---.-.-.-.`-_ # :-------------------------------------------------------------------------: # `---._.-------------------------------------------------------------._.---' # ---------------------------------------------------------------- ################################################################################################ # # .d8888b. 888 # d88P Y88b 888 # Y88b. 888 # "Y888b. 888 888 .d8888b 888888 .d88b. 88888b.d88b. # "Y88b. 888 888 88K 888 d8P Y8b 888 "888 "88b # "888 888 888 "Y8888b. 888 88888888 888 888 888 # Y88b d88P Y88b 888 X88 Y88b. Y8b. 888 888 888 # "Y8888P" "Y88888 88888P' "Y888 "Y8888 888 888 888 # 888 # Y8b d88P # "Y88P" # 888b d888 888 # 8888b d8888 888 # 88888b.d88888 888 # 888Y88888P888 8888b. 88888b. 8888b. .d88b. .d88b. 88888b.d88b. .d88b. 88888b. 888888 # 888 Y888P 888 "88b 888 "88b "88b d88P"88b d8P Y8b 888 "888 "88b d8P Y8b 888 "88b 888 # 888 Y8P 888 .d888888 888 888 .d888888 888 888 88888888 888 888 888 88888888 888 888 888 # 888 " 888 888 888 888 888 888 888 Y88b 888 Y8b. 888 888 888 Y8b. 888 888 Y88b. # 888 888 "Y888888 888 888 "Y888888 "Y88888 "Y8888 888 888 888 "Y8888 888 888 "Y888 # 888 # Y8b d88P # "Y88P" ################################################################################################ dependency::command_exists() { # Description: Checks if specified commands exist on the system and installs missing ones. # # This function checks if specified commands are available on the system. If any commands are missing, # it prompts the user to install them. The function supports both terminal and GUI prompts based on # the session type. Additionally, it can automatically install missing commands without prompting # the user when the `--auto` flag is used. # # Globals: # - None # Arguments: # - Command names to check (e.g., "command1 command2"). # - "--auto" (optional): Automatically installs missing commands without prompting. # Outputs: # - Prompts the user to install missing commands if any (unless `--auto` is specified). # Returns: # - 0 if all commands exist. # - 1 if any commands are missing and not installed. # # Usage: # dependency::command_exists [--auto] "command1 command2" # # Example: # dependency::command_exists "curl git" # dependency::command_exists --auto "curl git" # # Notes: # - This function detects the current session type (TTY, SSH, GUI, WAYLAND) to determine # the appropriate prompt method. # - Uses `zenity` for GUI prompts if available. # - Prompts the user to install missing commands and attempts to install them # using `system::install_missing_commands`. # - The `--auto` flag suppresses prompts and automatically installs missing commands. # # End of Documentation local _auto_mode=0 # Check for the --auto flag if [[ "$1" == "--auto" ]]; then _auto_mode=1 shift fi # List of required commands from input local required_commands=("$@") # Collect any missing commands local missing_commands=() for cmd in "${required_commands[@]}"; do if ! command -v "$cmd" &>/dev/null ; then missing_commands+=("$cmd") fi done # If none are missing, we’re good if [[ ${#missing_commands[@]} -eq 0 ]]; then return 0 fi # If in auto mode, just install them (no prompt) if [[ $_auto_mode -eq 1 ]]; then write_status "Installing missing commands: ${missing_commands[*]}" system::install_missing_commands "${missing_commands[@]}" return $? fi # Otherwise, prompt the user once local session_type session_type=$(system::detect_session) local prompt_text="${#missing_commands[@]} command(s) missing: ${missing_commands[*]}.\nInstall now? [y/N]: " local user_response="" # Use zenity if in GUI/Wayland (and if `zenity` is available) if [[ "$session_type" =~ ^(GUI|WAYLAND)$ ]] && command -v zenity &>/dev/null; then if ! zenity --question \ --title="Missing Commands" \ --text="The following commands are missing: ${missing_commands[*]}. \nInstall now?" \ 2>/dev/null; then write_error "Required command(s) not found: ${missing_commands[*]}" return 1 fi else # TTY / SSH or fallback read -r -p "$(echo -e "$prompt_text")" user_response # Convert to lowercase user_response="${user_response,,}" if [[ "$user_response" != "y" && "$user_response" != "yes" ]]; then write_error "Required command(s) not found: ${missing_commands[*]}" return 1 fi fi # Attempt install, return based on success/failure system::install_missing_commands "${missing_commands[@]}" return $? } dependency::desktop() { # Description: Identifies the currently running desktop environment. # # This function simplifies the process of determining the desktop environment currently in use. # It addresses the inconsistencies in using environment variables such as DESKTOP_SESSION and GDMSESSION. # The function checks multiple sources to reliably identify the running desktop environment. # # Globals: # - None # Arguments: # - "$1": The desktop environment to check for (e.g., gnome, kde, xfce, mate). # Outputs: # - Logs the process of identifying the desktop environment. # Returns: # - 0 if the specified desktop environment is found. # - 1 if the specified desktop environment is not found. # # Usage: # dependency::desktop # # Example: # dependency::desktop gnome # Check if there is a running GNOME desktop session # dependency::desktop kde # Check if there is a running KDE desktop session # dependency::desktop xfce # Check if there is a running Xfce desktop session # dependency::desktop mate # Check if there is a running MATE desktop session # # Dependencies: # - system::log_item: For logging the process of identifying the desktop environment. # # Notes: # This function checks various environment variables and processes to identify the desktop # environment.It first attempts to use XDG_CURRENT_DESKTOP. If that is unset, it searches # for known desktop processes. # The function checks for the following desktop environments: # - KDE # - GNOME # - MATE # - Xfce # - Cinnamon # - LXDE # - LXQt # - Unity # - Pantheon # - Sway # - Enlightenment # - Openbox # - IceWM # - Fluxbox # - JWM # # Reference: # The main problem with checking the DESKTOP_SESSION is that it is set by the display # manager rather than the desktop session and is subject to inconsistencies. # For lightdm on Debian, the values come from the names of files under /usr/share/xsessions/. # DESKTOP_SESSION reflects the desktop environment if a specific selection is made at log in, # however the lightdm-xsession is always used the default session. # # GDMSESSION is another option, but seems to have a similar predicament # (it is often the same value as DESKTOP_SESSION). # # XDG_CURRENT_DESKTOP looks like a good choice, however it is currently not in the XDG # standard and thus not always implemented. See here for a discussion of this. This # answer shows its values for different distros/desktops. # # The reasonable fallback for XDG_CURRENT_DESKTOP not existing would be to try # XDG_DATA_DIRS. Provided the data files for the desktop environment are installed # in a directory bearing its name, this approach should work. This will hopefully # be the case for all distros/desktops! # # End of documentation local _sought="${1,,}" [[ -z "${_sought}" ]] && { system::log_item "No desktop environment specified to check for."; return 1; } system::log_item "checking if there is a running $_sought desktop session..." local detected="" # Prefer XDG_CURRENT_DESKTOP when set; normalize tokens and allow colon/semicolon separators. if [[ -n "$XDG_CURRENT_DESKTOP" ]]; then for token in ${XDG_CURRENT_DESKTOP//[:;]/ }; do token="${token,,}" [[ -z "$detected" ]] && detected="$token" if [[ "$token" == *"$_sought"* ]]; then system::log_item "Found desktop via XDG_CURRENT_DESKTOP: $token" return 0 fi done else system::log_item "XDG_CURRENT_DESKTOP appears to be unset, attempting to search processes for desktop match..." fi # Fallback: look for well-known session processes with exact matches to avoid false positives. local proc_map=( "plasmashell:kde" "gnome-shell:gnome" "mate-session:mate" "xfce4-session:xfce" "cinnamon:cinnamon" "lxsession:lxde" "lxqt-session:lxqt" "unity-panel-service:unity" "pantheon-session:pantheon" "sway:sway" "enlightenment:enlightenment" "openbox:openbox" "icewm:icewm" "fluxbox:fluxbox" "jwm:jwm" ) for entry in "${proc_map[@]}"; do local proc="${entry%%:*}" local name="${entry##*:}" if pgrep -x "$proc" &>/dev/null; then detected="$name" break fi done system::log_item "Found: detected=${detected:-unknown}" local detected_lc="${detected,,}" if [[ -n "$detected_lc" && "$detected_lc" == *"$_sought"* ]]; then return 0 fi return 1 } desktop::apply_user_tweaks() { # Description: # Dispatch user-facing tweaks depending on the active desktop environment. # Non-interactive by default; with --interactive will present a small menu. # Arguments: # --desktop : Override detected desktop. # --interactive : Show dialog menu of available tweaks. # Outputs: Status messages or a menu selection applied. # Returns: 0 on success, non-zero on error/cancel. local desktop="" local interactive=0 while [[ $# -gt 0 ]]; do case "$1" in --desktop) desktop="${2,,}"; shift 2 ;; --interactive) interactive=1; shift ;; *) shift ;; esac done if [[ -z "$desktop" ]]; then if dependency::desktop gnome; then desktop="gnome" elif dependency::desktop kde; then desktop="kde" fi fi if [[ -z "$desktop" ]]; then write_error "Unable to detect desktop (GNOME/KDE). Use --desktop to override." return 1 fi if [[ $interactive -eq 1 ]] && dependency::command_exists dialog; then if [[ "$desktop" == "gnome" ]]; then local choices=( "common" "Apply core GNOME tweaks (themes/icons/ui)." "win10" "Apply Windows 10 styled GNOME tweaks." "mac" "Apply macOS styled GNOME tweaks." ) exec 3>&1 local sel sel=$(dialog --backtitle "${BRANDING:-RTD Power Tools}" \ --title "GNOME Tweaks" \ --menu "Select tweak set to apply:" 15 70 5 "${choices[@]}" 2>&1 1>&3) exec 3>&- case "$sel" in common) gnome::set_ui_common_tweaks_for_user ;; win10) gnome::set_ui_win10_tweaks_for_user ;; mac) gnome::set_ui_mac_tweaks_for_user ;; *) write_information "No tweak applied."; return 0 ;; esac return $? elif [[ "$desktop" == "kde" ]]; then local choices=( "lnf" "Look & Feel (Breeze Dark)." "color" "Color scheme (BreezeDark)." "icon" "Icon theme (breeze-dark)." "wall" "Wallpaper (prompt for file)." "fonts" "Font AA (hintmedium/rgb)." ) exec 3>&1 local sel sel=$(dialog --backtitle "${BRANDING:-RTD Power Tools}" \ --title "KDE Tweaks" \ --menu "Select tweak to apply:" 16 70 6 "${choices[@]}" 2>&1 1>&3) exec 3>&- case "$sel" in lnf) kde::set_global_look_and_feel --package org.kde.breezedark.desktop ;; color) kde::set_color_scheme --scheme BreezeDark ;; icon) kde::set_icon_theme --theme breeze-dark ;; wall) exec 3>&1 local wp wp=$(dialog --backtitle "${BRANDING:-RTD Power Tools}" --title "Wallpaper" --fselect "${HOME}/" 12 70 2>&1 1>&3) exec 3>&- [[ -n "$wp" ]] && kde::set_wallpaper "$wp" ;; fonts) kde::tune_fonts_antialias --hintstyle hintmedium --subpixel rgb ;; *) write_information "No tweak applied."; return 0 ;; esac return $? fi fi # Non-interactive summary if [[ "$desktop" == "gnome" ]]; then write_information "Detected GNOME. Available tweaks (non-interactive mode):" write_information " - gnome::set_ui_common_tweaks_for_user" write_information " - gnome::set_ui_win10_tweaks_for_user" write_information " - gnome::set_ui_mac_tweaks_for_user" elif [[ "$desktop" == "kde" ]]; then write_information "Detected KDE. Available tweaks (non-interactive mode):" write_information " - kde::set_global_look_and_feel --package " write_information " - kde::set_color_scheme --scheme " write_information " - kde::set_icon_theme --theme " write_information " - kde::set_wallpaper " write_information " - kde::tune_fonts_antialias --hintstyle