Last active
May 1, 2026 19:47
-
-
Save zeppelin/99b0eac12273c4091fd35f67eb0be224 to your computer and use it in GitHub Desktop.
ubuntu-mbp-2015.sh
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
| #!/usr/bin/env bash | |
| # | |
| # mac-ubuntu-setup.sh — Post-install Mac hardware support for Ubuntu | |
| # | |
| # Tested on 2015 MacBook Pro (MacBookPro12,1 / 11,4 / 11,5) with Ubuntu 24.04 LTS. | |
| # Likely works on other Intel MacBook Pro models 2011–2017. | |
| # | |
| # What it does: | |
| # 1. Updates apt package lists and upgrades installed packages | |
| # 2. Installs Broadcom Wi-Fi driver (bcmwl-kernel-source) | |
| # 3. Configures hid_apple so F-keys act as standard function keys | |
| # 4. Installs and enables mbpfan (Mac fan control daemon) | |
| # 5. Installs and enables TLP (laptop power management) | |
| # 6. Installs quality-of-life utilities (powertop, lm-sensors, dmidecode) | |
| # | |
| # Idempotent. Safe to re-run after kernel updates or fresh installs. | |
| # | |
| # Usage: | |
| # curl -fsSL https://gist.github.com/zeppelin/99b0eac12273c4091fd35f67eb0be224/raw -o mac-setup.sh | |
| # less mac-setup.sh # ALWAYS review before executing | |
| # bash mac-setup.sh # interactive (asks for confirmation) | |
| # bash mac-setup.sh -y # non-interactive | |
| # bash mac-setup.sh --help # show help | |
| # | |
| # Source: https://gist.github.com/zeppelin/99b0eac12273c4091fd35f67eb0be224 | |
| set -euo pipefail | |
| # ─── Config ────────────────────────────────────────────────────────────────── | |
| readonly SCRIPT_NAME="mac-ubuntu-setup" | |
| readonly SCRIPT_VERSION="1.0.0" | |
| LOG_FILE="/tmp/${SCRIPT_NAME}-$(date +%Y%m%d-%H%M%S).log" | |
| readonly LOG_FILE | |
| ASSUME_YES=0 | |
| NEEDS_REBOOT=0 | |
| CHANGES=() | |
| # ─── Output helpers ────────────────────────────────────────────────────────── | |
| if [[ -t 1 ]]; then | |
| BOLD=$'\033[1m'; DIM=$'\033[2m' | |
| RED=$'\033[0;31m'; GREEN=$'\033[0;32m' | |
| YELLOW=$'\033[0;33m'; BLUE=$'\033[0;34m' | |
| RESET=$'\033[0m' | |
| else | |
| BOLD='' DIM='' RED='' GREEN='' YELLOW='' BLUE='' RESET='' | |
| fi | |
| log() { printf "%s==>%s %s\n" "$BLUE" "$RESET" "$*" | tee -a "$LOG_FILE"; } | |
| ok() { printf "%s✓%s %s\n" "$GREEN" "$RESET" "$*" | tee -a "$LOG_FILE"; } | |
| warn() { printf "%s!%s %s\n" "$YELLOW" "$RESET" "$*" | tee -a "$LOG_FILE" >&2; } | |
| err() { printf "%s✗%s %s\n" "$RED" "$RESET" "$*" | tee -a "$LOG_FILE" >&2; } | |
| fatal() { err "$@"; exit 1; } | |
| note_change() { CHANGES+=("$1"); } | |
| # ─── CLI parsing ───────────────────────────────────────────────────────────── | |
| usage() { | |
| cat <<EOF | |
| ${BOLD}${SCRIPT_NAME}${RESET} v${SCRIPT_VERSION} | |
| Post-install Mac hardware support for Ubuntu. | |
| Usage: bash $0 [OPTIONS] | |
| Options: | |
| -y, --yes Run non-interactively (assume yes to prompts) | |
| -h, --help Show this help and exit | |
| Log file: ${LOG_FILE} | |
| EOF | |
| } | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| -y|--yes) ASSUME_YES=1; shift ;; | |
| -h|--help) usage; exit 0 ;; | |
| *) err "Unknown argument: $1"; usage; exit 1 ;; | |
| esac | |
| done | |
| confirm() { | |
| local prompt="$1" | |
| if [[ $ASSUME_YES -eq 1 ]]; then return 0; fi | |
| if [[ ! -t 0 ]]; then | |
| warn "Non-interactive stdin and -y not given; assuming yes" | |
| return 0 | |
| fi | |
| read -r -p "$prompt [Y/n] " reply | |
| [[ -z "$reply" || "$reply" =~ ^[Yy]$ ]] | |
| } | |
| # ─── Preflight ─────────────────────────────────────────────────────────────── | |
| preflight() { | |
| log "Preflight checks..." | |
| # OS | |
| [[ -f /etc/os-release ]] || fatal "/etc/os-release missing — unsupported system" | |
| # shellcheck disable=SC1091 | |
| . /etc/os-release | |
| [[ "${ID:-}" == "ubuntu" ]] || fatal "Ubuntu required (detected: ${ID:-unknown})" | |
| ok "OS: ${PRETTY_NAME}" | |
| # Network | |
| if ! ping -c1 -W2 archive.ubuntu.com >/dev/null 2>&1; then | |
| warn "No network connectivity to archive.ubuntu.com" | |
| warn "If Wi-Fi isn't working yet, tether via USB or use Ethernet adapter" | |
| confirm "Continue anyway?" || fatal "Aborted" | |
| fi | |
| # Sudo | |
| if [[ $EUID -eq 0 ]]; then | |
| warn "Running as root — recommended to run as your normal user instead" | |
| else | |
| log "Caching sudo credentials (you may be prompted)" | |
| sudo -v || fatal "Sudo authentication failed" | |
| # Keep sudo alive in background | |
| ( while true; do sudo -n true; sleep 60; kill -0 "$$" 2>/dev/null || exit; done ) & | |
| readonly SUDO_KEEPER_PID=$! | |
| # shellcheck disable=SC2064 | |
| trap "kill $SUDO_KEEPER_PID 2>/dev/null || true" EXIT | |
| fi | |
| # Hardware detection (best-effort) | |
| if ! command -v dmidecode >/dev/null 2>&1; then | |
| sudo apt-get install -y -qq dmidecode >/dev/null 2>&1 || true | |
| fi | |
| if command -v dmidecode >/dev/null 2>&1; then | |
| MAC_MODEL=$(sudo dmidecode -s system-product-name 2>/dev/null || echo unknown) | |
| ok "Hardware: ${MAC_MODEL}" | |
| if [[ ! "$MAC_MODEL" =~ ^MacBook ]]; then | |
| warn "This doesn't look like a MacBook (${MAC_MODEL})" | |
| confirm "Continue anyway?" || fatal "Aborted" | |
| fi | |
| fi | |
| log "Log file: ${LOG_FILE}" | |
| } | |
| # ─── Tasks ─────────────────────────────────────────────────────────────────── | |
| apt_update_upgrade() { | |
| log "Updating apt package lists..." | |
| sudo apt-get update -qq | |
| log "Upgrading installed packages (this may take a while)..." | |
| sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq | |
| ok "System packages up to date" | |
| } | |
| install_broadcom_wifi() { | |
| log "Configuring Broadcom Wi-Fi driver..." | |
| # Detect if a Broadcom wireless device exists | |
| if ! lspci -nn | grep -qiE 'Network controller.*Broadcom'; then | |
| warn "No Broadcom wireless adapter detected — skipping bcmwl" | |
| return 0 | |
| fi | |
| if dpkg -l bcmwl-kernel-source 2>/dev/null | grep -q '^ii'; then | |
| ok "bcmwl-kernel-source already installed" | |
| else | |
| log "Installing bcmwl-kernel-source..." | |
| sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq bcmwl-kernel-source | |
| note_change "Installed Broadcom Wi-Fi driver" | |
| fi | |
| # Reload modules — order matters | |
| log "Reloading wireless kernel modules..." | |
| sudo modprobe -r b43 ssb wl brcmfmac brcmsmac bcma 2>/dev/null || true | |
| sudo modprobe wl 2>/dev/null || warn "Failed to load 'wl' module — reboot may be required" | |
| ok "Broadcom Wi-Fi configured" | |
| } | |
| configure_function_keys() { | |
| log "Configuring function key behavior (fnmode=2: F-keys as F-keys)..." | |
| local conf=/etc/modprobe.d/hid_apple.conf | |
| local desired="options hid_apple fnmode=2" | |
| if [[ -f "$conf" ]] && grep -qF "$desired" "$conf"; then | |
| ok "hid_apple fnmode already configured" | |
| return 0 | |
| fi | |
| echo "$desired" | sudo tee "$conf" >/dev/null | |
| log "Rebuilding initramfs..." | |
| sudo update-initramfs -u -k all >/dev/null | |
| note_change "Set hid_apple fnmode=2 (reboot required)" | |
| NEEDS_REBOOT=1 | |
| ok "Function keys configured" | |
| } | |
| install_mbpfan() { | |
| log "Configuring fan control (mbpfan)..." | |
| if dpkg -l mbpfan 2>/dev/null | grep -q '^ii'; then | |
| ok "mbpfan already installed" | |
| else | |
| sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq mbpfan | |
| note_change "Installed mbpfan" | |
| fi | |
| if systemctl is-enabled mbpfan >/dev/null 2>&1; then | |
| ok "mbpfan service already enabled" | |
| else | |
| sudo systemctl enable --now mbpfan | |
| note_change "Enabled mbpfan service" | |
| fi | |
| } | |
| install_tlp() { | |
| log "Configuring power management (TLP)..." | |
| if dpkg -l tlp 2>/dev/null | grep -q '^ii'; then | |
| ok "TLP already installed" | |
| else | |
| sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq tlp tlp-rdw | |
| note_change "Installed TLP" | |
| fi | |
| if systemctl is-enabled tlp >/dev/null 2>&1; then | |
| ok "TLP service already enabled" | |
| else | |
| sudo systemctl enable --now tlp | |
| note_change "Enabled TLP service" | |
| fi | |
| } | |
| install_extras() { | |
| log "Installing quality-of-life utilities..." | |
| local pkgs=(powertop lm-sensors) | |
| local to_install=() | |
| for pkg in "${pkgs[@]}"; do | |
| if ! dpkg -l "$pkg" 2>/dev/null | grep -q '^ii'; then | |
| to_install+=("$pkg") | |
| fi | |
| done | |
| if [[ ${#to_install[@]} -eq 0 ]]; then | |
| ok "Extras already installed" | |
| return 0 | |
| fi | |
| sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq "${to_install[@]}" | |
| note_change "Installed: ${to_install[*]}" | |
| } | |
| # ─── Summary ───────────────────────────────────────────────────────────────── | |
| print_summary() { | |
| echo | |
| printf "%s%s──── Summary ────%s\n" "$BOLD" "$BLUE" "$RESET" | |
| if [[ ${#CHANGES[@]} -eq 0 ]]; then | |
| ok "Nothing to do — system already configured" | |
| else | |
| log "Changes applied:" | |
| for change in "${CHANGES[@]}"; do | |
| printf " %s•%s %s\n" "$DIM" "$RESET" "$change" | |
| done | |
| fi | |
| echo | |
| log "Log saved to: ${LOG_FILE}" | |
| if [[ $NEEDS_REBOOT -eq 1 ]]; then | |
| echo | |
| warn "${BOLD}Reboot required${RESET} for changes to take full effect" | |
| if confirm "Reboot now?"; then | |
| sudo systemctl reboot | |
| fi | |
| fi | |
| } | |
| # ─── Main ──────────────────────────────────────────────────────────────────── | |
| main() { | |
| printf "%s%s%s v%s%s\n" "$BOLD" "$BLUE" "$SCRIPT_NAME" "$SCRIPT_VERSION" "$RESET" | |
| echo | |
| cat <<EOF | |
| This script will: | |
| • Update the system (apt update && upgrade) | |
| • Install Broadcom Wi-Fi driver (if Broadcom hardware detected) | |
| • Configure F-keys as standard function keys | |
| • Install + enable mbpfan (fan control) | |
| • Install + enable TLP (power management) | |
| • Install powertop & lm-sensors | |
| EOF | |
| if ! confirm "Proceed?"; then | |
| log "Cancelled by user" | |
| exit 0 | |
| fi | |
| preflight | |
| apt_update_upgrade | |
| install_broadcom_wifi | |
| configure_function_keys | |
| install_mbpfan | |
| install_tlp | |
| install_extras | |
| print_summary | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment