LG Update Blocker

# LG Update Blocker A webOS homebrew app that gets rid of the *"a new software version is available"* popup LG shows on every boot — without touching the firmware itself, and fully reversible. Built for a rooted **LG CX (webOS 5)**, but nothing in it is model specific: it only ever probes for things and acts on what it actually finds on your TV. ![screenshot](docs/screenshot.png) ## Why the popup keeps coming back The Homebrew Channel's own *Block system updates* toggle only writes four hostnames into `/etc/hosts` at boot. That is not enough in practice: * it misses several update hostnames (`nsu`, `*-ssl`, the CDN aliases), * it does nothing about a firmware image the TV **already downloaded** — a staged update keeps prompting even when the update servers are unreachable, * it leaves the auto-update settings and the update services alone. This app covers all of that, and re-applies everything on each boot (webOS resets `/`, `/tmp` and the mount namespace on every start). ## Protection layers | Layer | What it does | Default | | --- | --- | --- | | **Block LG update servers** | Points `snu`/`su`/`nsu.lge.com`, their TLS variants, the `-dev` fallbacks and the CDN aliases at `127.0.0.1` in `/etc/hosts` | on | | **Delete staged firmware** | Wipes the update image staged in `/mnt/lg/cmn_data/swupdate` | on | | **Lock the staging folder** | Bind-mounts an empty read-only directory over it, so nothing can be staged again | off | | **Turn off auto-update settings** | Reads every `com.webos.settingsservice` category, switches off each update-related key it finds, and remembers the original values | on | | **Stop update services at boot** | Stops the update-related upstart jobs discovered in `/etc/init` (advanced) | off | Every layer is undone by **Remove protection**, which also restores the settings from the backup it made. ## Requirements * A rooted webOS TV with the [Homebrew Channel](https://github.com/webosbrew/webos-homebrew-channel) installed and its root status showing **ok**. * The app's own service needs root. On first launch it asks the Homebrew Channel to elevate it (`elevateService`, falling back to running `elevate-service` through `exec`), then restarts itself. The header badge turns green when it worked. ## Install ### Through the Homebrew Channel (repository) Add the repository once — *Homebrew Channel → Settings → Add repository*: ``` https://github.com///releases/latest/download/apps.json ``` The app then shows up in the Homebrew Channel list, and every new release you tag is picked up automatically (that URL always points at the newest release). ### Manually Download the `.ipk` from the release and: ```sh ares-install com.rkievits.lgupdateblocker_1.0.0_all.ipk ares-launch com.rkievits.lgupdateblocker ``` ## Using it Navigate with ▲▼, select with OK, leave with BACK. 1. Check the layers you want (the defaults are a good start). 2. **Apply protection** — the log pane shows exactly what was changed. 3. Reboot and confirm the popup is gone. Other buttons: **Purge staged update** (wipe a downloaded image right now), **Remove protection** (undo everything), **Refresh status**, and **Diagnostics** (dumps OS info, mounts, discovered settings, the tail of `/etc/hosts` and the boot-hook log — handy for a bug report). ## What it touches | Path | Purpose | | --- | --- | | `/etc/hosts` | Blocked hostnames, between `# >>> lg-update-blocker >>>` markers. Bind-mounted from `/tmp/lgupdateblocker-hosts` because `/` is read-only | | `/var/lib/webosbrew/init.d/lgupdateblocker` | Boot hook, run by the Homebrew Channel startup script; re-applies the enabled layers | | `/var/lib/webosbrew/lgupdateblocker/` | `config.json`, `hosts.txt`, `settings-backup.json`, `boot.log` | | `/mnt/lg/cmn_data/swupdate` | Staged firmware, emptied (and optionally locked) | Nothing is written to system partitions, and no LG binaries are patched or replaced. ## Troubleshooting * **Badge says "no root"** — open the Homebrew Channel, verify *Root status* is `ok`, then relaunch this app. If the Homebrew Channel itself is unelevated, fix that first (its Settings screen has a button for it). * **Popup still appears after a reboot** — run *Diagnostics* and look at the boot-hook log at the bottom. It records, per boot, whether the hosts entries were added, what was purged and which jobs were stopped. * **Belt and braces** — a hosts file only helps if the TV uses DNS. Blocking `snu.lge.com`, `su.lge.com` and `nsu.lge.com` on your router or Pi-hole as well is the one measure that also survives a factory reset. * **Forced *app* updates** (the *"You must update this app to launch it"* dialog) are a different mechanism — that is what [LG App Update Blocker](https://github.com/dr0dr1dr2dr3/lgappupdateblocker) is for. This app deliberately leaves the `lgtvsdp.com` hosts alone, since blocking those also breaks the store and several other services. ## Building No bundler, no runtime dependencies — `tools/build.js` copies `app/` and `service/` into `build/` and substitutes the app id and version. ```sh npm install # only the ares CLI npm run dist # build + package + manifest, output in dist/ npm run deploy # ares-install the resulting ipk ``` ## Releasing `.github/workflows/release.yml` builds on every push. Tag a commit `v` (matching `version` in `package.json`) and the workflow additionally publishes a release containing: * `com.rkievits.lgupdateblocker__all.ipk` * `com.rkievits.lgupdateblocker.manifest.json` — Homebrew Channel manifest, with the absolute ipk URL, its sha256 and size * `apps.json` — the one-package repository index used by the repository URL above * `description.html` — the long description shown in the Homebrew Channel The app id lives in exactly one place: the `name` field of `package.json`. Change it there and everything (appinfo, service name, Luna URIs, manifest) follows. ## License MIT