Initial commit

This commit is contained in:
Pipo 2025-09-24 17:18:02 +02:00
commit 0cd1cbb132
7 changed files with 148 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Pipo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

46
README.md Normal file
View file

@ -0,0 +1,46 @@
# auto-snapclean-listener
A small macOS utility script that automatically deletes all local Time Machine snapshots once they are created.
It is useful for users who do not want macOS to keep local snapshots and prefer to rely only on external Time Machine backups.
⚠️ Tested on **macOS Tahoe**. Other versions may work, but are not guaranteed.
---
## Features
- Listens for local Time Machine snapshot creation events.
- Waits until the backup process is finished (avoids conflicts).
- Automatically deletes all local snapshots afterwards.
- Lightweight: no constant polling, event-driven.
---
## Installation
Clone the repository:
```bash
git clone https://github.com/YOURUSERNAME/auto-snapclean-listener.git
cd auto-snapclean-listener
```
Make the script executable:
```bash
chmod +x auto-snapclean-listener.sh
```
Install the LaunchDaemon:
```bash
sudo cp auto-snapclean-listener.plist /Library/LaunchDaemons/
sudo launchctl load /Library/LaunchDaemons/auto-snapclean-listener.plist
```
Uninstall (if needed):
```bash
sudo launchctl unload /Library/LaunchDaemons/auto-snapclean-listener.plist
sudo rm /Library/LaunchDaemons/auto-snapclean-listener.plist
```

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.snapclean.listener</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/auto-snapclean-listener.sh</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>UserName</key><string>root</string>
</dict>
</plist>

View file

@ -0,0 +1,43 @@
#!/bin/zsh
set -euo pipefail
LOGF="/var/log/snapclean.log"
log() { print -r -- "$(date '+%F %T') $*" >> "$LOGF"; }
is_running() {
/usr/bin/tmutil status 2>/dev/null | /usr/bin/grep -Eq '"Running" = 1|Running = 1'
}
wait_until_tm_idle() {
local i=0
while is_running; do
sleep 2
(( i++ ))
[[ $i -gt 150 ]] && log "Timeout: TM still running. Waiting until it's finished." && break
done
}
delete_all_snapshots() {
log "Deletes all local Snapshots at / …"
/usr/bin/tmutil deletelocalsnapshots / || true
log "Finished deleting."
}
# Make sure logfile exists
[[ -f "$LOGF" ]] || { sudo touch "$LOGF"; sudo chmod 644 "$LOGF"; }
while IFS= read -r line; do
if print -r -- "$line" | /usr/bin/grep -q \
"com.apple.TimeMachine:LocalSnapshotManagement] Created Time Machine local snapshot"; then
log "Event erkannt: $line"
# Short break until the snapshot is in index
sleep 2
# Waiting until TM is finished
wait_until_tm_idle
# delete all local snapshots
delete_all_snapshots
fi
done < <(
/usr/bin/log stream --style syslog --level info \
--predicate 'process == "backupd" AND subsystem == "com.apple.TimeMachine"'
)

17
scripts/install.sh Normal file
View file

@ -0,0 +1,17 @@
#!/bin/zsh
set -euo pipefail
PLIST_SRC="$(cd -- "$(dirname "$0")/.." && pwd)/launchd/com.snapclean.listener.plist"
SCRIPT_SRC="$(cd -- "$(dirname "$0")/.." && pwd)/scripts/auto-snapclean-listener.sh"
sudo install -m 0755 "$SCRIPT_SRC" /usr/local/bin/auto-snapclean-listener.sh
sudo install -m 0644 "$PLIST_SRC" /Library/LaunchDaemons/com.snapclean.listener.plist
sudo touch /var/log/snapclean.log /var/log/snapclean.out /var/log/snapclean.err
sudo chmod 644 /var/log/snapclean.*
# (re)load
sudo launchctl unload /Library/LaunchDaemons/com.snapclean.listener.plist 2>/dev/null || true
sudo launchctl load -w /Library/LaunchDaemons/com.snapclean.listener.plist
sudo launchctl list | grep snapclean || true
echo "✅ snapcleaner installed."

6
scripts/uninstall.sh Normal file
View file

@ -0,0 +1,6 @@
#!/bin/zsh
set -euo pipefail
sudo launchctl unload /Library/LaunchDaemons/com.snapclean.listener.plist 2>/dev/null || true
sudo rm -f /Library/LaunchDaemons/com.snapclean.listener.plist
sudo rm -f /usr/local/bin/auto-snapclean-listener.sh
echo "✅ snapcleaner deleted. Logs stay in /var/log/snapclean.*"