From e39e5decb3023f47d85e3251d077c31c6ef67d60 Mon Sep 17 00:00:00 2001 From: Andrew Mello Date: Wed, 10 Jun 2026 16:16:21 -0400 Subject: [PATCH] Add --auto-resume: complete activation automatically after the BIOS-toggle reboot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the firmware refuses with AMT_STATUS_NOT_PERMITTED (manageability disabled in BIOS, e.g. P3 Ultra 30HA factory state), amt-activate now offers to finish the job itself: - stages the think-lmi BIOS toggle (tries ManageabilityControl, then AMTControl) so no BIOS menu visit is needed - installs a self-disabling one-shot amt-autoactivate.service that re-runs activation at next boot via the new --resume mode (reuses the saved password non-interactively, disables the unit on success, retries next boot if the toggle still is not live) - --auto-resume does the same without prompting, for headless/automation Also fixes a latent bug: rpc exits non-zero on refusal (Error 4 AmtNotReady), and under set -euo pipefail the activate|tee pipeline killed the script before any post-activation handling ran — including the NOT_PERMITTED hint added in #3. The pipeline now tolerates rpc's exit code and the handlers actually execute. Bumps script VERSION to 0.2.0. README: quick-start, Lenovo section, and troubleshooting row updated for the automatic path. --- README.md | 6 ++- scripts/amt-activate.sh | 103 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 101 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 842ffbc..ad15534 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ sudo amt-activate That's it. Tool checks state, generates a strong password, activates, verifies. ~40-90 seconds total. +If your BIOS ships with manageability disabled (e.g. ThinkStation P3 Ultra 30HA), `amt-activate` detects the firmware refusal, offers to stage the BIOS toggle from Linux, and installs a self-disabling systemd unit that finishes activation at the next boot — your only action is the reboot. Non-interactive environments: `sudo amt-activate --auto-resume` does the same without prompting. + **Headless / automation note:** in sessions without a TTY (CI, agents, `ssh host cmd`), yay builds fine but its final `pacman -U` dies on the interactive sudo prompt. Build then install explicitly: ```bash @@ -147,6 +149,8 @@ echo Enabled | sudo tee /sys/class/firmware-attributes/thinklmi/attributes/Manag The change is staged in NVRAM and takes effect at the **next POST** — running `rpc activate` before rebooting fails with `AMT_STATUS_NOT_PERMITTED` / `Error 4: AmtNotReady`. Reboot once, then activate. Still no BIOS menu visit required. +`amt-activate` ≥ 0.2.0 automates this whole branch: on `AmtNotReady` it stages the toggle (tries `ManageabilityControl`, then `AMTControl`) and enables a one-shot `amt-autoactivate.service` that re-runs activation at boot with your saved password and disables itself on success. + #### Dell | Line | Models | Local CCM | Notes | @@ -268,7 +272,7 @@ sudo rpc deactivate -local | Activation hangs 5-15 minutes | Expected on AMT 16.1.25 / AMT 18.x without LMS | Be patient. AMT 16.1.27 takes ~40s. AMT 18 may take 15 min per rpc-go #1119 | | Activation never completes on AMT 19+ | LME interface removed in CSME 19.x | Install LMS daemon: `yay -S intel-amt-linux` ships LMS in Docker | | `Execution timeout after 20s` × 3 then exit | AMT not in pre-provisioning, BIOS has AMT disabled, or OEM-preset MEBx password | Check `rpc amtinfo`; reset BIOS / Unconfigure AMT if MEBx is locked | -| `AMT_STATUS_NOT_PERMITTED` / `Error 4: AmtNotReady` on activate | Manageability disabled in BIOS — `rpc amtinfo` shows `Operational State: disabled`. ThinkStation P3 Ultra (30HA) ships this way from factory | Stage the BIOS toggle from Linux (Lenovo `think-lmi` / Dell `cctk`, see vendor table), reboot once, re-run `rpc activate -local -ccm` | +| `AMT_STATUS_NOT_PERMITTED` / `Error 4: AmtNotReady` on activate | Manageability disabled in BIOS — `rpc amtinfo` shows `Operational State: disabled`. ThinkStation P3 Ultra (30HA) ships this way from factory | `amt-activate` ≥ 0.2.0 offers to fix this automatically (stage toggle + resume unit + reboot). Manual: stage the BIOS toggle from Linux (Lenovo `think-lmi` / Dell `cctk`, see vendor table), reboot once, re-run `rpc activate -local -ccm` | | IP stays `0.0.0.0` after activation | DHCP not yet leased | Wait 30-60s, re-run `rpc amtinfo`. AMT NIC requests DHCP after CCM transition completes | | `401 Unauthorized` after activation | Known WiFi/802.1x sync bug on certain firmware | rpc-go #1310 — open issue as of May 2026 | | `wsmancli`/`openwsman` build fails on Arch | Upstream openwsman is dead since 2019; Ruby rdoc build crash | Use `rpc-go-bin` instead; do not install wsmancli on Arch | diff --git a/scripts/amt-activate.sh b/scripts/amt-activate.sh index 11b31b1..6435fff 100755 --- a/scripts/amt-activate.sh +++ b/scripts/amt-activate.sh @@ -12,23 +12,34 @@ set -euo pipefail -PW_FILE="${HOME}/.amt-mebx-password.txt" +PW_FILE="${AMT_PW_FILE:-${HOME}/.amt-mebx-password.txt}" LOG_FILE="/tmp/amt-activate.log" -VERSION="0.1.1" +VERSION="0.2.0" if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then cat <&2; exit 1; } info() { echo "${GRN}==>${RST} $*"; } warn() { echo "${YLW}WARN:${RST} $*"; } +# Stage the BIOS manageability toggle from Linux (Lenovo think-lmi). +# Attribute name varies by platform: ManageabilityControl (P3 Ultra 30HA), +# AMTControl (T14 Gen 2+, X1 Gen 9+, M90q Gen 2+). Applies at next POST. +stage_bios_toggle() { + local base=/sys/class/firmware-attributes/thinklmi/attributes attr + for attr in ManageabilityControl AMTControl; do + if [ -e "$base/$attr/current_value" ]; then + info "Staging BIOS toggle: $attr=Enabled (applies at next POST)" + echo Enabled | sudo tee "$base/$attr/current_value" >/dev/null && return 0 + fi + done + warn "No Lenovo think-lmi AMT attribute found." + echo " Dell: sudo cctk --AdvancedAmt=Enable" + echo " Other: enable AMT in BIOS setup once, then re-run amt-activate" + return 1 +} + +# Install a self-disabling one-shot unit so activation resumes at next boot. +install_resume_unit() { + local self; self=$(readlink -f "$0") + sudo tee /etc/systemd/system/amt-autoactivate.service >/dev/null </dev/null || true +} + # ── prerequisites ────────────────────────────────────────────────────────── [ -e /dev/mei0 ] || err "/dev/mei0 not found — run: sudo modprobe mei_me" command -v rpc &>/dev/null || err "'rpc' not found — install rpc-go-bin: yay -S rpc-go-bin" @@ -61,6 +121,7 @@ if echo "$AMT_INFO" | grep -qi "activated in client control mode"; then info "AMT already activated in CCM. Nothing to do." AMT_IP=$(echo "$AMT_INFO" | grep "AMT IP" | head -1 | awk '{print $NF}') echo "AMT IP: ${AMT_IP:-check router DHCP table}" + [[ "$MODE" == "resume" ]] && disable_resume_unit exit 0 fi @@ -68,7 +129,17 @@ echo "$AMT_INFO" | grep -qi "pre-provisioning" || \ err "AMT not in pre-provisioning state (may already be configured differently)" # ── password ─────────────────────────────────────────────────────────────── -if [ -f "$PW_FILE" ]; then +if [[ "$MODE" != "interactive" ]]; then + # resume/auto: never prompt — reuse the saved password or create one + if [ -f "$PW_FILE" ]; then + PW=$(cat "$PW_FILE") + else + PW=$(openssl rand -base64 18 | tr -d '/+=' | head -c 14) + PW="${PW}A9!x" + echo "$PW" > "$PW_FILE" + chmod 0600 "$PW_FILE" + fi +elif [ -f "$PW_FILE" ]; then warn "Password file already exists at $PW_FILE" read -rp " Use existing password? [Y/n] " yn if [[ "${yn:-y}" =~ ^[Nn] ]]; then @@ -97,14 +168,32 @@ echo " Two 'Execution timeout after 20s' warnings are normal." echo " Total time: ~40 seconds on CSME 16.x." echo "" -sudo rpc activate -local -ccm -password "$PW" 2>&1 | tee "$LOG_FILE" +# rpc exits non-zero on refusal (e.g. Error 4 AmtNotReady) — '|| true' keeps +# set -euo pipefail from killing the script before the handlers below run. +sudo rpc activate -local -ccm -password "$PW" 2>&1 | tee "$LOG_FILE" || true echo "" if grep -q "Device activated in Client Control Mode" "$LOG_FILE"; then info "Activation successful." + [[ "$MODE" == "resume" ]] && disable_resume_unit elif grep -qE "AMT_STATUS_NOT_PERMITTED|AmtNotReady" "$LOG_FILE"; then warn "Firmware refused activation: manageability is disabled in BIOS." - echo " Stage the toggle from Linux (no BIOS menu needed), reboot once, re-run:" + if [[ "$MODE" == "resume" ]]; then + # Toggle still not live (or staging never happened) — retry next boot. + warn "Leaving amt-autoactivate.service enabled for next boot." + exit 1 + fi + if [[ "$MODE" == "auto" ]]; then + stage_bios_toggle && install_resume_unit && exit 0 + exit 1 + fi + if [ -t 0 ]; then + read -rp " Stage the BIOS toggle now and finish automatically after reboot? [Y/n] " yn + if [[ ! "${yn:-y}" =~ ^[Nn] ]]; then + stage_bios_toggle && install_resume_unit && exit 0 + fi + fi + echo " Manual path — stage the toggle, reboot once, re-run amt-activate:" echo " Lenovo: ls /sys/class/firmware-attributes/thinklmi/attributes/ | grep -iE 'amt|manage'" echo " echo Enabled | sudo tee /sys/class/firmware-attributes/thinklmi/attributes/ManageabilityControl/current_value" echo " Dell: sudo cctk --AdvancedAmt=Enable"