Skip to content

Instantly share code, notes, and snippets.

@zeppelin
Last active May 1, 2026 19:47
Show Gist options
  • Select an option

  • Save zeppelin/99b0eac12273c4091fd35f67eb0be224 to your computer and use it in GitHub Desktop.

Select an option

Save zeppelin/99b0eac12273c4091fd35f67eb0be224 to your computer and use it in GitHub Desktop.
ubuntu-mbp-2015.sh
#!/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