Created
September 24, 2025 17:09
-
-
Save gustavomdsantos/3b693e1e012ccdee4410b20ea848479b to your computer and use it in GitHub Desktop.
Wi-Fi Manager - a systemd daemon for automating tasks with Linux wireless interfaces.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ============================================================================== | |
| # Script: wifi-manager-setup.sh | |
| # Description: Installer and uninstaller for the Wi-Fi management daemon. | |
| # Author: Gustavo Moraes <[email protected]> | |
| # ============================================================================== | |
| # --- Variables ---------------------------------------------------------------- | |
| DAEMON_SCRIPT="wifi-manager-daemon.sh" | |
| SERVICE_NAME="wifi-manager.service" | |
| SERVICE_FILE_PATH="/etc/systemd/system/${SERVICE_NAME}" | |
| DAEMON_PATH="/usr/local/bin/${DAEMON_SCRIPT}" | |
| # --- Utility Functions -------------------------------------------------------- | |
| # Displays a multi-line message using a single echo command. | |
| display_message() { | |
| local message="$1" | |
| echo -e "$message" | |
| } | |
| # Checks for required commands and provides helpful error messages. | |
| check_dependencies() { | |
| local missing_deps=() | |
| local required_deps=( | |
| "systemctl" | |
| "ip" | |
| "lsusb" | |
| "lspci" | |
| "awk" | |
| "grep" | |
| ) | |
| for dep in "${required_deps[@]}"; do | |
| if ! command -v "$dep" &> /dev/null; then | |
| missing_deps+=("$dep") | |
| fi | |
| done | |
| if [[ ${#missing_deps[@]} -ne 0 ]]; then | |
| local message | |
| message=$(cat <<EOF | |
| ERROR: The following required dependencies are not installed: | |
| $(printf "* %s\n" "${missing_deps[@]}") | |
| Please install them and try again. | |
| EOF | |
| ) | |
| display_message "$message" | |
| exit 1 | |
| fi | |
| } | |
| # Verifies if the script is running as root. | |
| check_root() { | |
| if [[ $EUID -ne 0 ]]; then | |
| display_message "ERROR: This script must be run as root. Please use 'sudo'." | |
| exit 1 | |
| fi | |
| } | |
| # --- Service Management Functions --------------------------------------------- | |
| # Creates and writes the systemd service file. | |
| create_service_file() { | |
| local service_content | |
| service_content=$(cat <<EOF | |
| [Unit] | |
| Description=Wi-Fi Manager Daemon | |
| After=network-online.target | |
| [Service] | |
| ExecStart=${DAEMON_PATH} | |
| Restart=on-failure | |
| RestartSec=5s | |
| User=root | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| ) | |
| echo "${service_content}" | tee "${SERVICE_FILE_PATH}" &>/dev/null | |
| if [[ $? -ne 0 ]]; then | |
| display_message "ERROR: Failed to create systemd service file at ${SERVICE_FILE_PATH}." | |
| exit 1 | |
| fi | |
| } | |
| # Installs the daemon and the systemd service. | |
| install_service() { | |
| display_message "--- Starting installation of the Wi-Fi Manager Daemon ---" | |
| if [[ -f "${DAEMON_PATH}" ]]; then | |
| display_message "INFO: Daemon script already exists. Overwriting..." | |
| fi | |
| local daemon_script | |
| daemon_script=$(cat << 'EOF_DAEMON' | |
| #!/bin/bash | |
| # ============================================================================== | |
| # Script: wifi-manager-daemon.sh | |
| # Description: Daemon to manage Wi-Fi interfaces automatically. | |
| # Author: Gustavo Moraes <[email protected]> | |
| # ============================================================================== | |
| # --- Utility Functions -------------------------------------------------------- | |
| # Displays a multi-line message. This function is now local to the daemon. | |
| display_message() { | |
| local message="$1" | |
| echo -e "$message" | |
| } | |
| # Finds the internal PCI Wi-Fi interface. | |
| find_internal_wifi() { | |
| local pci_interfaces | |
| pci_interfaces=$(lspci | grep -i "wireless\|wi-fi\|network" | awk '{print $1}') | |
| for pci_id in ${pci_interfaces}; do | |
| local iface_name | |
| iface_name=$(ls -l /sys/class/net/ | grep "${pci_id}" | awk '{print $9}') | |
| if [[ -n "${iface_name}" ]] && [[ ! "${iface_name}" =~ ^wlx ]]; then | |
| echo "${iface_name}" | |
| return | |
| fi | |
| done | |
| } | |
| # Finds all USB Wi-Fi interfaces. | |
| find_usb_wifi() { | |
| local usb_interfaces=() | |
| local all_interfaces | |
| all_interfaces=$(ip -o link show | awk -F': ' '/wlx/ {print $2}') | |
| for iface in ${all_interfaces}; do | |
| usb_interfaces+=("${iface}") | |
| done | |
| echo "${usb_interfaces[@]}" | |
| } | |
| # Checks if a Wi-Fi interface exists and is enabled. | |
| is_interface_enabled() { | |
| local interface="$1" | |
| ip link show "$interface" &> /dev/null && ip link show "$interface" | grep -q "state UP" | |
| } | |
| # Brings a Wi-Fi interface up. | |
| enable_interface() { | |
| local interface="$1" | |
| if ! is_interface_enabled "${interface}"; then | |
| if ! ip link set "$interface" up; then | |
| display_message "ERROR: Failed to enable interface '$interface'." | |
| fi | |
| fi | |
| } | |
| # Brings a Wi-Fi interface down. | |
| disable_interface() { | |
| local interface="$1" | |
| if is_interface_enabled "${interface}"; then | |
| if ! ip link set "$interface" down; then | |
| display_message "ERROR: Failed to disable interface '$interface'." | |
| fi | |
| fi | |
| } | |
| # --- Main Logic --------------------------------------------------------------- | |
| display_message "INFO: Wi-Fi manager daemon started." | |
| # Declare variables for state management. | |
| internal_interface="" | |
| usb_interfaces=() | |
| usb_connected=false | |
| current_state="unknown" | |
| while true; do | |
| internal_interface=$(find_internal_wifi) | |
| usb_interfaces=($(find_usb_wifi)) | |
| usb_connected=false | |
| if [[ -z "${internal_interface}" ]]; then | |
| display_message "ERROR: Could not find the internal Wi-Fi interface. The daemon will exit." | |
| exit 1 | |
| fi | |
| # Check for the presence of any active USB Wi-Fi interface | |
| for iface in "${usb_interfaces[@]}"; do | |
| if ip link show "${iface}" &> /dev/null; then | |
| usb_connected=true | |
| break | |
| fi | |
| done | |
| if ${usb_connected}; then | |
| if [[ "${current_state}" != "usb" ]]; then | |
| display_message "INFO: USB Wi-Fi adapter detected. Disabling internal interface '${internal_interface}'." | |
| disable_interface "${internal_interface}" | |
| current_state="usb" | |
| fi | |
| else | |
| if [[ "${current_state}" != "internal" ]]; then | |
| display_message "INFO: No USB Wi-Fi adapter found. Enabling internal interface '${internal_interface}'." | |
| enable_interface "${internal_interface}" | |
| current_state="internal" | |
| fi | |
| fi | |
| # Check for changes every 2 seconds. | |
| sleep 2 | |
| done | |
| EOF_DAEMON | |
| ) | |
| echo "${daemon_script}" | tee "${DAEMON_PATH}" &>/dev/null | |
| if [[ $? -ne 0 ]]; then | |
| display_message "ERROR: Failed to write daemon script to ${DAEMON_PATH}." | |
| exit 1 | |
| fi | |
| chmod +x "${DAEMON_PATH}" | |
| create_service_file | |
| display_message "INFO: Reloading systemd daemon..." | |
| systemctl daemon-reload | |
| display_message "INFO: Enabling the Wi-Fi Manager service..." | |
| systemctl enable "${SERVICE_NAME}" | |
| display_message "INFO: Wi-Fi Manager daemon and service installed successfully." | |
| display_message "Use 'sudo systemctl status ${SERVICE_NAME}' to check its status." | |
| display_message "Installation complete." | |
| } | |
| # Uninstalls the daemon and the systemd service. | |
| uninstall_service() { | |
| display_message "--- Starting uninstallation of the Wi-Fi Manager Daemon ---" | |
| if systemctl is-active --quiet "${SERVICE_NAME}"; then | |
| display_message "INFO: Stopping the service..." | |
| systemctl stop "${SERVICE_NAME}" | |
| fi | |
| if systemctl is-enabled --quiet "${SERVICE_NAME}"; then | |
| display_message "INFO: Disabling the service..." | |
| systemctl disable "${SERVICE_NAME}" | |
| fi | |
| if [[ -f "${SERVICE_FILE_PATH}" ]]; then | |
| display_message "INFO: Removing systemd service file..." | |
| rm -f "${SERVICE_FILE_PATH}" | |
| fi | |
| if [[ -f "${DAEMON_PATH}" ]]; then | |
| display_message "INFO: Removing daemon script..." | |
| rm -f "${DAEMON_PATH}" | |
| fi | |
| display_message "INFO: Reloading systemd daemon..." | |
| systemctl daemon-reload | |
| display_message "INFO: All files have been removed." | |
| display_message "Uninstallation complete." | |
| } | |
| # Starts the systemd service. | |
| start_service() { | |
| check_root | |
| if [[ ! -f "${SERVICE_FILE_PATH}" ]]; then | |
| display_message "ERROR: Service file not found. Please run 'sudo ./wifi-manager-setup.sh install' first." | |
| exit 1 | |
| fi | |
| display_message "INFO: Starting the Wi-Fi Manager service..." | |
| systemctl enable "${SERVICE_NAME}" | |
| systemctl start "${SERVICE_NAME}" | |
| display_message "INFO: Service started. Use 'sudo systemctl status ${SERVICE_NAME}' to check its status." | |
| } | |
| # Stops the systemd service. | |
| stop_service() { | |
| check_root | |
| if [[ ! -f "${SERVICE_FILE_PATH}" ]]; then | |
| display_message "ERROR: Service file not found. It seems the daemon is not installed." | |
| exit 1 | |
| fi | |
| display_message "INFO: Stopping the Wi-Fi Manager service..." | |
| systemctl stop "${SERVICE_NAME}" | |
| display_message "INFO: Service stopped." | |
| } | |
| # --- Main Logic (Command Parsing) --------------------------------------------- | |
| main() { | |
| if [[ -z "$1" ]]; then | |
| local usage_message | |
| usage_message=$(cat <<EOF | |
| Usage: $0 {install|uninstall|start|stop} | |
| Commands: | |
| install Installs the daemon script and systemd service. | |
| uninstall Uninstalls the daemon script and systemd service. | |
| start Starts the daemon service (must be installed first). | |
| stop Stops the daemon service. | |
| EOF | |
| ) | |
| display_message "$usage_message" | |
| exit 1 | |
| fi | |
| case "$1" in | |
| install) | |
| check_root | |
| check_dependencies | |
| install_service | |
| ;; | |
| uninstall) | |
| check_root | |
| uninstall_service | |
| ;; | |
| start) | |
| start_service | |
| ;; | |
| stop) | |
| stop_service | |
| ;; | |
| *) | |
| display_message "ERROR: Invalid command '$1'. Use 'install', 'uninstall', 'start' or 'stop'." | |
| exit 1 | |
| ;; | |
| esac | |
| } | |
| main "$@" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment