From e0442c56b97432cb659e0d8b09e2e9d44d3c0e4e Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Mon, 12 Oct 2026 00:07:07 +0200 Subject: [PATCH] fix(packaging): stop the service before the package is removed Removing the package left the user service running from the deleted binary, with ~/ProtonDrive still mounted. A user who then deleted the folder to clean up had every file in it moved to the Proton Drive trash, as any delete through the mount is. The .deb (prerm on remove), the .rpm (%preun on erase) and the Arch packages (pre_remove) now stop proton-drive.service for every user with a running user manager, through runuser with that user's XDG_RUNTIME_DIR, so no systemd-machined is needed. Upgrades are left alone. Queued writes stay in the state directory for a later install. The pacman install script lives once in packaging/ and the AUR directories link it; push.sh copies its content into each AUR repository. The uninstall guide now warns not to delete the mount point while the service runs. Reported on Reddit by a user who restored the files from the trash. --- .github/workflows/release.yml | 3 +++ docs/CHANGELOG.md | 4 ++++ docs/INSTALL.md | 11 ++++++++-- packaging/PKGBUILD | 2 ++ packaging/aur/README.md | 3 ++- .../aur/proton-drive-for-linux-bin/.SRCINFO | 1 + .../aur/proton-drive-for-linux-bin/.gitignore | 1 + .../aur/proton-drive-for-linux-bin/PKGBUILD | 2 ++ .../proton-drive.install | 1 + .../aur/proton-drive-for-linux-git/.SRCINFO | 1 + .../aur/proton-drive-for-linux-git/.gitignore | 1 + .../aur/proton-drive-for-linux-git/PKGBUILD | 2 ++ .../proton-drive.install | 1 + packaging/aur/proton-drive-for-linux/.SRCINFO | 1 + .../aur/proton-drive-for-linux/.gitignore | 1 + packaging/aur/proton-drive-for-linux/PKGBUILD | 2 ++ .../proton-drive.install | 1 + packaging/aur/push.sh | 6 +++-- packaging/deb/prerm | 22 +++++++++++++++++++ packaging/proton-drive-linux.spec | 19 ++++++++++++++++ packaging/proton-drive.install | 19 ++++++++++++++++ 21 files changed, 99 insertions(+), 5 deletions(-) create mode 120000 packaging/aur/proton-drive-for-linux-bin/proton-drive.install create mode 120000 packaging/aur/proton-drive-for-linux-git/proton-drive.install create mode 120000 packaging/aur/proton-drive-for-linux/proton-drive.install create mode 100755 packaging/deb/prerm create mode 100644 packaging/proton-drive.install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f9b766..3b6d542 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -153,6 +153,9 @@ jobs: cp LICENSE deb/usr/share/licenses/proton-drive-linux/ po/build.sh deb/usr/share/locale + # Stops the running daemon before removal, so the mount stops mirroring deletes + install -m755 packaging/deb/prerm deb/DEBIAN/prerm + # Calculate Installed-Size in KB for the control file INSTALLED_SIZE=$(du -sk deb | cut -f1) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index fded422..f87a964 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -18,6 +18,10 @@ scratch (user data in `staging/` and `recovery/` is never touched by this). ([#37](https://github.com/narrrl/proton-drive-linux/issues/37)) ### Fixed +- **Removing the package left the drive mounted, and deletes there still reached Proton Drive.** + The service kept running from the removed program, so deleting `~/ProtonDrive` afterwards moved + its files to the Proton Drive trash. The .deb, .rpm and Arch packages now stop the service of + every logged-in user before they are removed. Upgrades are not affected. - **The Fedora package installed KDE packages on GNOME.** Its recommendation of KWallet is now only for Plasma, the GNOME keyring only for desktops other than Plasma, and the AppIndicator extension only for GNOME. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 23a5f01..8ec4eb7 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -302,8 +302,15 @@ pdfs logout # removes the session from the ``` Then remove the package (`sudo apt remove proton-drive-linux`, `sudo dnf remove -proton-drive-linux`, or `sudo pacman -R proton-drive-for-linux`), and, if you want no trace left, -the local data: +proton-drive-linux`, or `sudo pacman -R proton-drive-for-linux`). Removing the package also stops +the service of every logged-in user, in case a step above was skipped. + +> [!CAUTION] +> Do not delete `~/ProtonDrive` while it is mounted. It is your Proton Drive, not a copy: every +> file deleted there is moved to the Proton Drive trash. Once the service is stopped the folder is +> an empty mount point, and removing it is safe. + +If you want no trace left, remove the local data as well: ```bash rm -rf ~/.config/proton-drive-linux ~/.local/state/proton-drive-linux ~/.cache/proton-drive-linux diff --git a/packaging/PKGBUILD b/packaging/PKGBUILD index 07ff80b..8cf271f 100644 --- a/packaging/PKGBUILD +++ b/packaging/PKGBUILD @@ -26,6 +26,8 @@ optdepends=('gnome-keyring: credential storage via Secret Service' 'fzf: live search-as-you-type launcher (pdfs-prompt --fzf)' 'foot: terminal for pdfs-prompt --fzf started from a keybinding') options=('!lto' '!debug') +# Stops the running daemon before removal, so the mount stops mirroring deletes. +install=proton-drive.install # Built in place from the checkout; nothing to fetch or checksum. source=() diff --git a/packaging/aur/README.md b/packaging/aur/README.md index d725b50..e097466 100644 --- a/packaging/aur/README.md +++ b/packaging/aur/README.md @@ -13,7 +13,8 @@ The three packages conflict with each other and with the in-tree `packaging/PKGBUILD` package (`proton-drive-linux`), and every one of them `provides` `proton-drive-for-linux`, `proton-drive-linux`, and `pdfs`. -Each directory tracks only `PKGBUILD`, `.SRCINFO`, `.gitignore`, and `LICENSE` +Each directory tracks only `PKGBUILD`, `.SRCINFO`, `.gitignore`, `LICENSE` and +`proton-drive.install` (a link to `packaging/proton-drive.install`, copied as a file on push) (the 0BSD license of the packaging sources, per [RFC40](https://rfc.archlinux.page/0040-license-package-sources/)); the `.gitignore` ignores everything else so downloaded sources, `src/`, `pkg/`, and diff --git a/packaging/aur/proton-drive-for-linux-bin/.SRCINFO b/packaging/aur/proton-drive-for-linux-bin/.SRCINFO index 3475d64..cf9c3be 100644 --- a/packaging/aur/proton-drive-for-linux-bin/.SRCINFO +++ b/packaging/aur/proton-drive-for-linux-bin/.SRCINFO @@ -3,6 +3,7 @@ pkgbase = proton-drive-for-linux-bin pkgver = 3.3.0 pkgrel = 1 url = https://proton-drive.narl.io + install = proton-drive.install arch = x86_64 license = MIT depends = fuse3 diff --git a/packaging/aur/proton-drive-for-linux-bin/.gitignore b/packaging/aur/proton-drive-for-linux-bin/.gitignore index 68dbfe4..4a236f6 100644 --- a/packaging/aur/proton-drive-for-linux-bin/.gitignore +++ b/packaging/aur/proton-drive-for-linux-bin/.gitignore @@ -5,3 +5,4 @@ !.SRCINFO !LICENSE !PKGBUILD +!proton-drive.install diff --git a/packaging/aur/proton-drive-for-linux-bin/PKGBUILD b/packaging/aur/proton-drive-for-linux-bin/PKGBUILD index b4e9fdb..4cfe446 100644 --- a/packaging/aur/proton-drive-for-linux-bin/PKGBUILD +++ b/packaging/aur/proton-drive-for-linux-bin/PKGBUILD @@ -22,6 +22,8 @@ provides=("${pkgname%-bin}=$pkgver" "proton-drive-linux=$pkgver" 'pdfs') conflicts=('proton-drive-linux' 'proton-drive-for-linux' 'proton-drive-for-linux-git') # Upstream ships the binaries already built on Ubuntu 24.04; do not rewrite them. options=('!strip' '!debug') +# Stops the running daemon before removal, so the mount stops mirroring deletes. +install=proton-drive.install _tag="v$pkgver" _raw="https://raw.githubusercontent.com/narrrl/proton-drive-linux/$_tag" # The release tarball holds the four binaries only, so the desktop integration diff --git a/packaging/aur/proton-drive-for-linux-bin/proton-drive.install b/packaging/aur/proton-drive-for-linux-bin/proton-drive.install new file mode 120000 index 0000000..2b484b0 --- /dev/null +++ b/packaging/aur/proton-drive-for-linux-bin/proton-drive.install @@ -0,0 +1 @@ +../../proton-drive.install \ No newline at end of file diff --git a/packaging/aur/proton-drive-for-linux-git/.SRCINFO b/packaging/aur/proton-drive-for-linux-git/.SRCINFO index 1d9f327..6fa2667 100644 --- a/packaging/aur/proton-drive-for-linux-git/.SRCINFO +++ b/packaging/aur/proton-drive-for-linux-git/.SRCINFO @@ -3,6 +3,7 @@ pkgbase = proton-drive-for-linux-git pkgver = 3.3.0.r0.g160626b pkgrel = 1 url = https://proton-drive.narl.io + install = proton-drive.install arch = x86_64 license = MIT makedepends = cargo diff --git a/packaging/aur/proton-drive-for-linux-git/.gitignore b/packaging/aur/proton-drive-for-linux-git/.gitignore index 68dbfe4..4a236f6 100644 --- a/packaging/aur/proton-drive-for-linux-git/.gitignore +++ b/packaging/aur/proton-drive-for-linux-git/.gitignore @@ -5,3 +5,4 @@ !.SRCINFO !LICENSE !PKGBUILD +!proton-drive.install diff --git a/packaging/aur/proton-drive-for-linux-git/PKGBUILD b/packaging/aur/proton-drive-for-linux-git/PKGBUILD index d5d73cf..4b46ea8 100644 --- a/packaging/aur/proton-drive-for-linux-git/PKGBUILD +++ b/packaging/aur/proton-drive-for-linux-git/PKGBUILD @@ -23,6 +23,8 @@ provides=("${pkgname%-git}=$pkgver" "proton-drive-linux=$pkgver" 'pdfs') conflicts=('proton-drive-linux' 'proton-drive-for-linux' 'proton-drive-for-linux-bin') # LTO has broken GTK/Rust links for this workspace; the release profile keeps it off. options=('!lto') +# Stops the running daemon before removal, so the mount stops mirroring deletes. +install=proton-drive.install source=("$pkgname::git+$_repo.git") sha256sums=('SKIP') diff --git a/packaging/aur/proton-drive-for-linux-git/proton-drive.install b/packaging/aur/proton-drive-for-linux-git/proton-drive.install new file mode 120000 index 0000000..2b484b0 --- /dev/null +++ b/packaging/aur/proton-drive-for-linux-git/proton-drive.install @@ -0,0 +1 @@ +../../proton-drive.install \ No newline at end of file diff --git a/packaging/aur/proton-drive-for-linux/.SRCINFO b/packaging/aur/proton-drive-for-linux/.SRCINFO index 496c8e4..5829715 100644 --- a/packaging/aur/proton-drive-for-linux/.SRCINFO +++ b/packaging/aur/proton-drive-for-linux/.SRCINFO @@ -3,6 +3,7 @@ pkgbase = proton-drive-for-linux pkgver = 3.3.0 pkgrel = 1 url = https://proton-drive.narl.io + install = proton-drive.install arch = x86_64 license = MIT makedepends = cargo diff --git a/packaging/aur/proton-drive-for-linux/.gitignore b/packaging/aur/proton-drive-for-linux/.gitignore index 68dbfe4..4a236f6 100644 --- a/packaging/aur/proton-drive-for-linux/.gitignore +++ b/packaging/aur/proton-drive-for-linux/.gitignore @@ -5,3 +5,4 @@ !.SRCINFO !LICENSE !PKGBUILD +!proton-drive.install diff --git a/packaging/aur/proton-drive-for-linux/PKGBUILD b/packaging/aur/proton-drive-for-linux/PKGBUILD index f42e6e4..7e49411 100644 --- a/packaging/aur/proton-drive-for-linux/PKGBUILD +++ b/packaging/aur/proton-drive-for-linux/PKGBUILD @@ -23,6 +23,8 @@ provides=("proton-drive-linux=$pkgver" 'pdfs') conflicts=('proton-drive-linux' 'proton-drive-for-linux-bin' 'proton-drive-for-linux-git') # LTO has broken GTK/Rust links for this workspace; the release profile keeps it off. options=('!lto') +# Stops the running daemon before removal, so the mount stops mirroring deletes. +install=proton-drive.install source=("$pkgname-$pkgver.tar.gz::$_repo/archive/refs/tags/v$pkgver.tar.gz") sha256sums=('ef58e96e64697917168f111958aaadf01c8eaac9fb482d0f6e70dfdc8ed4f167') diff --git a/packaging/aur/proton-drive-for-linux/proton-drive.install b/packaging/aur/proton-drive-for-linux/proton-drive.install new file mode 120000 index 0000000..2b484b0 --- /dev/null +++ b/packaging/aur/proton-drive-for-linux/proton-drive.install @@ -0,0 +1 @@ +../../proton-drive.install \ No newline at end of file diff --git a/packaging/aur/push.sh b/packaging/aur/push.sh index b32d37a..4682679 100755 --- a/packaging/aur/push.sh +++ b/packaging/aur/push.sh @@ -21,9 +21,11 @@ for pkg in "${packages[@]}"; do # A fresh clone every time: the AUR repository, not this checkout, is what the # commit history has to build on. git -c init.defaultBranch=master clone -q "ssh://aur@aur.archlinux.org/$pkg.git" "$workdir/$pkg" - install -m644 "$pkg/PKGBUILD" "$pkg/.SRCINFO" "$pkg/.gitignore" "$pkg/LICENSE" "$workdir/$pkg/" + # proton-drive.install is a link into packaging/; install copies its content. + install -m644 "$pkg/PKGBUILD" "$pkg/.SRCINFO" "$pkg/.gitignore" "$pkg/LICENSE" \ + "$pkg/proton-drive.install" "$workdir/$pkg/" - git -C "$workdir/$pkg" add -f PKGBUILD .SRCINFO .gitignore LICENSE + git -C "$workdir/$pkg" add -f PKGBUILD .SRCINFO .gitignore LICENSE proton-drive.install if git -C "$workdir/$pkg" diff --cached --quiet; then echo "$pkg: no changes" continue diff --git a/packaging/deb/prerm b/packaging/deb/prerm new file mode 100755 index 0000000..9ff38dd --- /dev/null +++ b/packaging/deb/prerm @@ -0,0 +1,22 @@ +#!/bin/sh +# Removing the package does not stop a running daemon: it keeps serving the +# mount from the deleted binary, so files deleted under the mount afterwards, +# `rm -rf ~/ProtonDrive` included, are still deleted on Proton Drive. Stop every +# logged-in user's service first; anything still queued stays on disk for the +# next install. Same loop as packaging/proton-drive.install. +set -e + +case "$1" in + remove) ;; + *) exit 0 ;; +esac + +for dir in /run/user/*; do + user=$(id -nu "${dir##*/}" 2>/dev/null) || continue + if runuser -u "$user" -- env XDG_RUNTIME_DIR="$dir" \ + systemctl --user --quiet is-active proton-drive.service 2>/dev/null; then + echo "Stopping Proton Drive for $user, which unmounts its drive." + runuser -u "$user" -- env XDG_RUNTIME_DIR="$dir" \ + systemctl --user stop proton-drive.service 2>/dev/null || : + fi +done diff --git a/packaging/proton-drive-linux.spec b/packaging/proton-drive-linux.spec index 7c88d6b..84e52c5 100644 --- a/packaging/proton-drive-linux.spec +++ b/packaging/proton-drive-linux.spec @@ -92,6 +92,25 @@ install -D -m0644 %{git_dir}/packaging/proton-drive.service \ %{buildroot}/usr/lib/systemd/user/proton-drive.service %{git_dir}/po/build.sh %{buildroot}%{_datadir}/locale +# Removing the package does not stop a running daemon: it keeps serving the +# mount from the deleted binary, so files deleted under the mount afterwards, +# `rm -rf ~/ProtonDrive` included, are still deleted on Proton Drive. Stop every +# logged-in user's service first; anything still queued stays on disk for the +# next install. $1 is 0 on an erase and 1 on an upgrade. Same loop as +# packaging/proton-drive.install. +%preun +if [ "$1" -eq 0 ]; then + for dir in /run/user/*; do + user=$(id -nu "${dir##*/}" 2>/dev/null) || continue + if runuser -u "$user" -- env XDG_RUNTIME_DIR="$dir" \ + systemctl --user --quiet is-active proton-drive.service 2>/dev/null; then + echo "Stopping Proton Drive for $user, which unmounts its drive." + runuser -u "$user" -- env XDG_RUNTIME_DIR="$dir" \ + systemctl --user stop proton-drive.service 2>/dev/null || : + fi + done +fi + %files %license LICENSE %{_bindir}/pdfs diff --git a/packaging/proton-drive.install b/packaging/proton-drive.install new file mode 100644 index 0000000..b20e1c1 --- /dev/null +++ b/packaging/proton-drive.install @@ -0,0 +1,19 @@ +# pacman install script, shared by packaging/PKGBUILD and the three AUR packages +# (each links it). The same loop is in packaging/deb/prerm and the RPM %preun. + +# Removing the package does not stop a running daemon: it keeps serving the +# mount from the deleted binary, so files deleted under the mount afterwards, +# `rm -rf ~/ProtonDrive` included, are still deleted on Proton Drive. Stop every +# logged-in user's service first; anything still queued stays on disk for the +# next install. Upgrades call pre_upgrade, not this. +pre_remove() { + for dir in /run/user/*; do + user=$(id -nu "${dir##*/}" 2>/dev/null) || continue + if runuser -u "$user" -- env XDG_RUNTIME_DIR="$dir" \ + systemctl --user --quiet is-active proton-drive.service 2>/dev/null; then + echo "Stopping Proton Drive for $user, which unmounts its drive." + runuser -u "$user" -- env XDG_RUNTIME_DIR="$dir" \ + systemctl --user stop proton-drive.service 2>/dev/null || : + fi + done +}