├── INSTALL ├── LICENSE ├── MIT ├── Makefile ├── README.md ├── common ├── browsers │ ├── chromium │ ├── chromium-dev │ ├── conkeror.mozdev.org │ ├── epiphany │ ├── falkon │ ├── firefox │ ├── firefox-trunk │ ├── google-chrome │ ├── google-chrome-beta │ ├── google-chrome-unstable │ ├── heftig-aurora │ ├── icecat │ ├── inox │ ├── luakit │ ├── midori │ ├── opera │ ├── opera-beta │ ├── opera-developer │ ├── opera-legacy │ ├── opera-next │ ├── otter-browser │ ├── palemoon │ ├── qupzilla │ ├── qutebrowser │ ├── rekonq │ ├── seamonkey │ ├── surf │ ├── vivaldi │ └── vivaldi-snapshot ├── debian │ ├── README │ ├── postinst │ ├── preinst │ └── prerm ├── profile-sync-daemon.in ├── psd-overlay-helper ├── psd-suspend-sync ├── psd.conf └── zsh-completion ├── contrib ├── brave ├── floorp ├── microsoft-edge ├── microsoft-edge-beta ├── thorium ├── vscode └── zen ├── doc ├── psd-overlay-helper.1 └── psd.1 └── init ├── psd-resync.service ├── psd-resync.timer └── psd.service /INSTALL: -------------------------------------------------------------------------------- 1 | DEPENDENCIES 2 | bash >=4.0 3 | coreutils 4 | findutils 5 | glib2 (optional for suspend-sync support via gdbus) 6 | kmod 7 | rsync 8 | systemd 9 | 10 | WARNING 11 | To avoid data loss, it is HIGHLY recommended that users stop any running 12 | versions of this software before install updates. Internal changes are 13 | always possible from one release to another. 14 | 15 | BUILDING 16 | Setup the via a make. 17 | 18 | $ make 19 | 20 | Running a `make install` as root will distribute the files to the filesystem. 21 | 22 | # make install 23 | 24 | Note that it is not required in many case, but on occasion, internals are 25 | changed in the psd code which makes users stopping any active psd session 26 | BEFORE the make install setup a good idea. 27 | 28 | Users of Arch/Chakra/Antergos and graysky's PPA (Ubuntu/Debian) do not 29 | need to worry about this as the respective package managers will do 30 | this for you. The Fedora packages should also have this built it. 31 | 32 | USE A DISTRO PROVIDED PACKAGE 33 | See the project homepage for an updated list of provided packages: 34 | https://github.com/graysky2/profile-sync-daemon 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All files in this software are licensed under The MIT License. 2 | -------------------------------------------------------------------------------- /MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2024 graysky 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION = 6.51 2 | PN = profile-sync-daemon 3 | 4 | PREFIX ?= /usr 5 | INITDIR_SYSTEMD = /usr/lib/systemd/user 6 | BINDIR = $(PREFIX)/bin 7 | SHAREDIR = $(PREFIX)/share/psd 8 | MANDIR = $(PREFIX)/share/man/man1 9 | ZSHDIR = $(PREFIX)/share/zsh/site-functions 10 | CONTRIBDIR = $(SHAREDIR)/contrib 11 | 12 | RM = rm 13 | SED = sed 14 | INSTALL = install -p 15 | INSTALL_PROGRAM = $(INSTALL) -m755 16 | INSTALL_SCRIPT = $(INSTALL) -m755 17 | INSTALL_DATA = $(INSTALL) -m644 18 | INSTALL_DIR = $(INSTALL) -d 19 | RSYNC = rsync -a 20 | Q = @ 21 | 22 | common/$(PN): common/$(PN).in 23 | $(Q)echo -e '\033[1;32mSetting version\033[0m' 24 | $(Q)$(SED) 's/@VERSION@/'$(VERSION)'/' common/$(PN).in > common/$(PN) 25 | 26 | install-bin: common/$(PN) 27 | $(Q)echo -e '\033[1;32mInstalling main script...\033[0m' 28 | $(INSTALL_DIR) "$(DESTDIR)$(BINDIR)" 29 | $(INSTALL_PROGRAM) common/$(PN) "$(DESTDIR)$(BINDIR)/$(PN)" 30 | $(INSTALL_PROGRAM) common/psd-overlay-helper "$(DESTDIR)$(BINDIR)/psd-overlay-helper" 31 | $(INSTALL_PROGRAM) common/psd-suspend-sync "$(DESTDIR)$(BINDIR)/psd-suspend-sync" 32 | ln -sf $(PN) "$(DESTDIR)$(BINDIR)/psd" 33 | $(INSTALL_DIR) "$(DESTDIR)$(ZSHDIR)" 34 | $(INSTALL_DATA) common/zsh-completion "$(DESTDIR)/$(ZSHDIR)/_psd" 35 | $(INSTALL_DIR) "$(DESTDIR)$(SHAREDIR)/browsers" 36 | $(INSTALL_DATA) common/psd.conf "$(DESTDIR)$(SHAREDIR)/psd.conf" 37 | $(INSTALL_DATA) common/browsers/* "$(DESTDIR)$(SHAREDIR)/browsers" 38 | $(INSTALL_DIR) "$(DESTDIR)$(SHAREDIR)/contrib" 39 | $(INSTALL_DATA) contrib/* "$(DESTDIR)$(SHAREDIR)/contrib" 40 | 41 | install-man: 42 | $(Q)echo -e '\033[1;32mInstalling manpage...\033[0m' 43 | $(INSTALL_DIR) "$(DESTDIR)$(MANDIR)" 44 | $(INSTALL_DATA) doc/psd.1 "$(DESTDIR)$(MANDIR)/psd.1" 45 | $(INSTALL_DATA) doc/psd-overlay-helper.1 "$(DESTDIR)$(MANDIR)/psd-overlay-helper.1" 46 | ln -sf psd.1 "$(DESTDIR)$(MANDIR)/$(PN).1" 47 | 48 | install-systemd: 49 | $(Q)echo -e '\033[1;32mInstalling systemd files...\033[0m' 50 | $(INSTALL_DIR) "$(DESTDIR)$(INITDIR_SYSTEMD)" 51 | $(INSTALL_DATA) init/psd.service "$(DESTDIR)$(INITDIR_SYSTEMD)/psd.service" 52 | $(INSTALL_DATA) init/psd-resync.service "$(DESTDIR)$(INITDIR_SYSTEMD)/psd-resync.service" 53 | $(INSTALL_DATA) init/psd-resync.timer "$(DESTDIR)$(INITDIR_SYSTEMD)/psd-resync.timer" 54 | 55 | install: install-bin install-man install-systemd 56 | 57 | uninstall-bin: 58 | $(RM) "$(DESTDIR)$(BINDIR)/$(PN)" 59 | $(RM) "$(DESTDIR)$(BINDIR)/psd" 60 | $(RM) "$(DESTDIR)$(ZSHDIR)/_psd" 61 | $(RM) "$(DESTDIR)$(BINDIR)/psd-overlay-helper" 62 | $(RM) "$(DESTDIR)$(BINDIR)/psd-suspend-sync" 63 | $(RM) "$(DESTDIR)$(SHAREDIR)/psd.conf" 64 | $(RM) -rf "$(DESTDIR)$(SHAREDIR)/browsers" 65 | $(RM) -rf "$(DESTDIR)$(SHAREDIR)/contrib" 66 | rmdir "$(DESTDIR)$(SHAREDIR)" 67 | 68 | uninstall-man: 69 | $(RM) -f "$(DESTDIR)$(MANDIR)/$(PN).1" 70 | $(RM) -f "$(DESTDIR)$(MANDIR)/psd.1" 71 | $(RM) -f "$(DESTDIR)$(MANDIR)/psd-overlay-helper.1" 72 | 73 | uninstall-systemd: 74 | $(RM) "$(DESTDIR)$(INITDIR_SYSTEMD)/psd.service" 75 | $(RM) "$(DESTDIR)$(INITDIR_SYSTEMD)/psd-resync.service" 76 | $(RM) "$(DESTDIR)$(INITDIR_SYSTEMD)/psd-resync.timer" 77 | 78 | uninstall: uninstall-bin uninstall-man uninstall-systemd 79 | 80 | clean: 81 | $(RM) -f common/$(PN) 82 | 83 | .PHONY: install-bin install-man install-systemd install uninstall-bin uninstall-man uninstall-systemd uninstall clean 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Profile-sync-daemon 2 | Profile-sync-daemon (psd) is a tiny pseudo-daemon designed to manage your browser's profile in tmpfs and to periodically sync it back to your physical disc (HDD/SSD). This is accomplished via a symlinking step and an innovative use of rsync to maintain back-up and synchronization between the two. One of the major design goals of psd is a completely transparent user experience. 3 | 4 | ## Good Advice 5 | Always backup your browser profile(s) before using psd for the first time. 6 | 7 | ## Users of eCryptFS 8 | User of eCryptFS are encouraged not to use psd unless willing to help troubleshoot suspected browser corruption. See [#158](https://github.com/graysky2/profile-sync-daemon/issues/158). 9 | 10 | ## Supported Browsers 11 | * Chromium 12 | * Conkeror 13 | * Epiphany 14 | * Firefox (stable, beta, and aurora) 15 | * Firefox-trunk (this is an Ubuntu-only browser: http://www.webupd8.org/2011/05/install-firefox-nightly-from-ubuntu-ppa.html) 16 | * Google Chrome (stable, beta, and dev) 17 | * Heftig's version of Aurora (this is an Arch Linux-only browser: https://bbs.archlinux.org/viewtopic.php?id=117157) 18 | * Icecat (GNU version of Firefox) 19 | * Iceweasel (Debian version of Firefox) 20 | * Inox (https://bbs.archlinux.org/viewtopic.php?id=198763) 21 | * Luakit 22 | * Midori 23 | * Opera, Opera-Beta, Opera-Developer, and Opera-Legacy 24 | * Otter-browser 25 | * Palemoon 26 | * QupZilla 27 | * Qutebrowser 28 | * Rekonq 29 | * Seamonkey 30 | * Surf (http://surf.suckless.org/) 31 | * Vivaldi-browser and Vivaldi-browser-snapshot 32 | 33 | ## Documentation 34 | Consult the man page or the wiki page: https://wiki.archlinux.org/index.php/Profile-sync-daemon 35 | 36 | ## Installation from Source 37 | To build from source, see the included INSTALL text document. 38 | 39 | ## Installation from Distro Packages 40 | ### Officially Packaged 41 | * Arch: in the extra [repo](https://archlinux.org/packages/extra/any/profile-sync-daemon/). 42 | * Debian: in the official [repos](https://packages.debian.org/unstable/profile-sync-daemon). 43 | * Exherbo: in the official [repos](http://git.exherbo.org/summer/packages/net-www/profile-sync-daemon). 44 | * Fedora: in the official [repos](https://src.fedoraproject.org/rpms/profile-sync-daemon). 45 | * Gentoo: in the official [repos](http://packages.gentoo.org/package/www-misc/profile-sync-daemon). 46 | * NixOS: in the official [repo](https://search.nixos.org/packages?channel=22.11&from=0&size=50&sort=relevance&type=packages&query=profile-sync). 47 | * Ubuntu: in Universe [repo](https://packages.ubuntu.com/search?keywords=profile-sync-daemon). 48 | 49 | ### User Packaged 50 | * Slackware: on [slackbuilds](http://slackbuilds.org/apps/profile-sync-daemon/). 51 | 52 | ### Other Distros 53 | If you are interested in packaging psd for your favorite distro, please contact me. 54 | 55 | ## logcheck 56 | Using logcheck? Here are some ways to filter out log lines: 57 | ```regexp 58 | ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ profile-sync-daemon\[[0-9]+]\]: .*(google-chrome|firefox) (re|un)sync successful 59 | ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ profile-sync-daemon\[[0-9]+\]: psd startup check successful$ 60 | ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ systemd\[[0-9]+\]: Started Timer for profile-sync-daemon 61 | ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ systemd\[[0-9]+\]: psd(-resync)?\.service: Consumed [0-9\.]+s CPU time\.$ 62 | ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ systemd\[[0-9]+\]: psd(-resync)\.timer: Succeeded\.$ 63 | ``` 64 | -------------------------------------------------------------------------------- /common/browsers/chromium: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/chromium-dev: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/conkeror.mozdev.org: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$HOME/.$browser" 2 | PSNAME="xulrunner" 3 | -------------------------------------------------------------------------------- /common/browsers/epiphany: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_DATA_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/falkon: -------------------------------------------------------------------------------- 1 | [[ -d $XDG_CONFIG_HOME/$browser ]] && 2 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 3 | PSNAME="$browser" 4 | -------------------------------------------------------------------------------- /common/browsers/firefox: -------------------------------------------------------------------------------- 1 | if [[ -d "$HOME"/.mozilla/firefox ]]; then 2 | index=0 3 | PSNAME="$browser" 4 | while read -r profileItem; do 5 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 6 | # path is not relative 7 | DIRArr[$index]="$profileItem" 8 | else 9 | # we need to append the default path to give a 10 | # fully qualified path 11 | DIRArr[$index]="$HOME/.mozilla/firefox/$profileItem" 12 | fi 13 | (( index=index+1 )) 14 | done < <(grep '[Pp]'ath= "$HOME"/.mozilla/firefox/profiles.ini | sed 's/[Pp]ath=//') 15 | fi 16 | 17 | check_suffix=1 -------------------------------------------------------------------------------- /common/browsers/firefox-trunk: -------------------------------------------------------------------------------- 1 | if [[ -d $HOME/.mozilla/firefox-trunk ]]; then 2 | index=0 3 | PSNAME="$browser" 4 | while read -r profileItem; do 5 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 6 | # path is not relative 7 | DIRArr[$index]="$profileItem" 8 | else 9 | # we need to append the default path to give a 10 | # fully qualified path 11 | DIRArr[$index]="$HOME/.mozilla/firefox-trunk/$profileItem" 12 | fi 13 | (( index=index+1 )) 14 | done < <(grep '[Pp]'ath= "$HOME"/.mozilla/firefox-trunk/profiles.ini | sed 's/[Pp]ath=//') 15 | fi 16 | 17 | check_suffix=1 18 | -------------------------------------------------------------------------------- /common/browsers/google-chrome: -------------------------------------------------------------------------------- 1 | if [[ -n "$CHROME_CONFIG_HOME" ]]; then 2 | DIRArr[0]="$CHROME_CONFIG_HOME/$browser" 3 | else 4 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 5 | fi 6 | PSNAME="chrome" 7 | -------------------------------------------------------------------------------- /common/browsers/google-chrome-beta: -------------------------------------------------------------------------------- 1 | if [[ -n "$CHROME_CONFIG_HOME" ]]; then 2 | DIRArr[0]="$CHROME_CONFIG_HOME/$browser" 3 | else 4 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 5 | fi 6 | PSNAME="chrome" 7 | -------------------------------------------------------------------------------- /common/browsers/google-chrome-unstable: -------------------------------------------------------------------------------- 1 | if [[ -n "$CHROME_CONFIG_HOME" ]]; then 2 | DIRArr[0]="$CHROME_CONFIG_HOME/$browser" 3 | else 4 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 5 | fi 6 | PSNAME="chrome" 7 | -------------------------------------------------------------------------------- /common/browsers/heftig-aurora: -------------------------------------------------------------------------------- 1 | # https://bbs.archlinux.org/viewtopic.php?id=117157 2 | if [[ -d "$HOME"/.mozilla/aurora ]]; then 3 | index=0 4 | PSNAME="aurora" 5 | while read -r profileItem; do 6 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 7 | # path is not relative 8 | DIRArr[$index]="$profileItem" 9 | else 10 | # we need to append the default path to give a 11 | # fully qualified path 12 | DIRArr[$index]="$HOME/.mozilla/aurora/$profileItem" 13 | fi 14 | (( index=index+1 )) 15 | done < <(grep '[Pp]'ath= "$HOME"/.mozilla/firefox/profiles.ini | sed 's/[Pp]ath=//') 16 | 17 | fi 18 | 19 | check_suffix=1 -------------------------------------------------------------------------------- /common/browsers/icecat: -------------------------------------------------------------------------------- 1 | if [[ -d $HOME/.mozilla/icecat ]]; then 2 | index=0 3 | PSNAME="$browser" 4 | while read -r profileItem; do 5 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 6 | # path is not relative 7 | DIRArr[$index]="$profileItem" 8 | else 9 | # we need to append the default path to give a 10 | # fully qualified path 11 | DIRArr[$index]="$HOME/.mozilla/icecat/$profileItem" 12 | fi 13 | (( index=index+1 )) 14 | done < <(grep '[Pp]'ath= "$HOME"/.mozilla/icecat/profiles.ini | sed 's/[Pp]ath=//') 15 | fi 16 | 17 | check_suffix=1 18 | -------------------------------------------------------------------------------- /common/browsers/inox: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/luakit: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$HOME/.local/share/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/midori: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/opera: -------------------------------------------------------------------------------- 1 | # version 26 moved the profile dir but keep this for older versions 2 | DIRArr[0]="$HOME/.$browser" 3 | DIRArr[1]="$XDG_CONFIG_HOME/$browser" 4 | PSNAME="$browser" 5 | -------------------------------------------------------------------------------- /common/browsers/opera-beta: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/opera-developer: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/opera-legacy: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$HOME/.$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/opera-next: -------------------------------------------------------------------------------- 1 | # version 26 moved the profile dir but keep this for older versions 2 | DIRArr[0]="$HOME/.$browser" 3 | DIRArr[1]="$XDG_CONFIG_HOME/$browser" 4 | PSNAME="$browser" 5 | -------------------------------------------------------------------------------- /common/browsers/otter-browser: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/otter" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/palemoon: -------------------------------------------------------------------------------- 1 | if [[ -d $HOME/.moonchild\ productions/pale\ moon ]]; then 2 | index=0 3 | PSNAME="$browser" 4 | while read -r profileItem; do 5 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 6 | # path is not relative 7 | DIRArr[$index]="$profileItem" 8 | else 9 | # we need to append the default path to give a 10 | # fully qualified path 11 | DIRArr[$index]="$HOME/.moonchild productions/pale moon/$profileItem" 12 | fi 13 | (( index=index+1 )) 14 | done < <(grep '[Pp]'ath= "$HOME"/.moonchild\ productions/pale\ moon/profiles.ini | sed 's/[Pp]ath=//') 15 | fi 16 | 17 | check_suffix=1 18 | -------------------------------------------------------------------------------- /common/browsers/qupzilla: -------------------------------------------------------------------------------- 1 | # http://blog.qupzilla.com/2013/03/qupzilla-140-released.html 2 | [[ -d $HOME/.$browser ]] && 3 | DIRArr[0]="$HOME/.$browser" 4 | [[ -d $XDG_CONFIG_HOME/$browser ]] && 5 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 6 | PSNAME="$browser" 7 | -------------------------------------------------------------------------------- /common/browsers/qutebrowser: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$HOME/.local/share/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/rekonq: -------------------------------------------------------------------------------- 1 | [[ -d $HOME/.kde4/share/apps/$browser ]] && 2 | DIRArr[0]="$HOME/.kde4/share/apps/$browser" 3 | [[ -d $HOME/.kde/share/apps/$browser ]] && 4 | DIRArr[0]="$HOME/.kde/share/apps/$browser" 5 | PSNAME="$browser" 6 | -------------------------------------------------------------------------------- /common/browsers/seamonkey: -------------------------------------------------------------------------------- 1 | if [[ -d $HOME/.mozilla/seamonkey ]]; then 2 | index=0 3 | PSNAME="$browser" 4 | while read -r profileItem; do 5 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 6 | # path is not relative 7 | DIRArr[$index]="$profileItem" 8 | else 9 | # we need to append the default path to give a 10 | # fully qualified path 11 | DIRArr[$index]="$HOME/.mozilla/seamonkey/$profileItem" 12 | fi 13 | (( index=index+1 )) 14 | done < <(grep '[Pp]'ath= "$HOME"/.mozilla/seamonkey/profiles.ini | sed 's/[Pp]ath=//') 15 | fi 16 | 17 | check_suffix=1 18 | -------------------------------------------------------------------------------- /common/browsers/surf: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$HOME/.$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /common/browsers/vivaldi: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser"-bin 3 | -------------------------------------------------------------------------------- /common/browsers/vivaldi-snapshot: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/vivaldi-snapshot" 2 | PSNAME="vivaldi-bin" 3 | -------------------------------------------------------------------------------- /common/debian/README: -------------------------------------------------------------------------------- 1 | These are just scripts that the ubuntu/debian packager needs. 2 | -------------------------------------------------------------------------------- /common/debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ -f /etc/psd.conf ]; then 5 | mv /etc/psd.conf /etc/psd.conf.old 6 | echo 'ATTENTION: MAJOR CHANGES TO PSD WITH VERSION 6.00+' 7 | echo '-> 1. A global /etc/psd.conf is no longer used. $HOME/.config/psd/psd.conf will be' 8 | echo '-> created when psd is invoked the first time.' 9 | echo '-> 2. A system service is no longer used. A user service is provided and can be' 10 | echo '-> used like this: systemctl --user start psd.service' 11 | echo '-> 3. Users wanting to use overlayfs mode MUST have sudo access with nopasswd to' 12 | echo '-> /usr/bin/psd-overlay-helper. See the man page for an example configured with visudo.' 13 | fi 14 | 15 | for i in $(users); do 16 | su $i -s /bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$UID systemctl --user daemon-reload' 17 | return 0 18 | done 19 | 20 | -------------------------------------------------------------------------------- /common/debian/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | case "$1" in 4 | install|upgrade) 5 | # version 6 is a user daemon so clear out old system level files 6 | 7 | if [ -f /usr/lib/systemd/system/psd.service ]; then 8 | [ "$(systemctl is-enabled psd)" = "enabled" ] && 9 | systemctl disable psd.service &>/dev/null 10 | 11 | [ "$(systemctl is-active psd)" = "active" ] && 12 | systemctl stop psd.service &>/dev/null 13 | fi 14 | 15 | for i in $(users); do 16 | if [ "$(su $i -s /bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$UID systemctl --user is-active psd')" = "active" ]; then 17 | echo "--> Internal changes to psd require it to be stopped before the update." 18 | echo "--> Restart it manually: systemctl --user start psd" 19 | su $i -s /bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$UID systemctl --user stop psd.service' 20 | fi 21 | return 0 22 | done 23 | 24 | ;; 25 | 26 | abort-upgrade) 27 | /bin/true 28 | ;; 29 | 30 | *) 31 | echo "preinst called with unknown argument \`$1'" >&2 32 | exit 1 33 | ;; 34 | esac 35 | exit 0 36 | -------------------------------------------------------------------------------- /common/debian/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | # summary of how this script can be called: 4 | # * `remove' 5 | # * `upgrade' 6 | # * `failed-upgrade' 7 | # * `remove' `in-favour' 8 | # * `deconfigure' `in-favour' 9 | # `removing' 10 | # 11 | # for details, see http://www.debian.org/doc/debian-policy/ or 12 | # the debian-policy package 13 | 14 | case "$1" in 15 | remove) 16 | for i in $(users); do 17 | if [ "$(su $i -s /bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$UID systemctl --user is-active psd')" = "active" ]; then 18 | echo "--> In order to preserve your profiles, psd service will be stopped now." 19 | echo "--> Any running and managed browsers will be exited." 20 | su $i -s /bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$UID systemctl --user stop psd.service' 21 | su $i -s /bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$UID systemctl --user disable psd.service' 22 | fi 23 | return 0 24 | done 25 | ;; 26 | upgrade|failed-upgrade) 27 | /bin/true 28 | # Do nothing 29 | ;; 30 | *) 31 | echo "prerm called with unknown argument \`$1'" >&2 32 | exit 1 33 | ;; 34 | esac 35 | 36 | exit 0 37 | -------------------------------------------------------------------------------- /common/profile-sync-daemon.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Profile-sync-daemon by graysky 5 | # Inspired by some code originally written by Colin Verot 6 | # 7 | 8 | # shellcheck disable=1090,2154 9 | 10 | # needed for debian >=8.x 11 | PATH=$PATH:/sbin 12 | 13 | if [[ -n "$LAUNCHED_BY_SYSTEMD" ]] ; then 14 | # This script was invoked by systemd 15 | # Thx to notes-jj: https://serverfault.com/questions/926349/systemd-tell-if-script-was-run-by-systemd-or-by-user 16 | # No 'echo' ANSI escape codes 17 | BLD='' 18 | RED='' 19 | GRN='' 20 | BLU='' 21 | NRM='' 22 | else 23 | BLD="\e[01m" 24 | RED="\e[01;31m" 25 | GRN="\e[01;32m" 26 | BLU="\e[01;34m" 27 | NRM="\e[00m" 28 | fi 29 | VERS="@VERSION@" 30 | 31 | user=$(id -un) 32 | HOME="$(getent passwd "$user" | cut -d: -f6)" 33 | TMPDIR="${TMPDIR:-/tmp}" 34 | XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" 35 | XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" 36 | PSDCONFDIR="$XDG_CONFIG_HOME/psd" 37 | PSDCONF="$PSDCONFDIR/psd.conf" 38 | SHAREDIR="/usr/share/psd" 39 | 40 | if [[ ! -d "$SHAREDIR" ]]; then 41 | echo -e " ${RED}ERROR:${NRM}${BLD} Missing ${BLU}$SHAREDIR${NRM}${BLD} - reinstall the package to use profile-sync-daemon.${NRM}" 42 | exit 1 43 | fi 44 | 45 | if [[ ! -d "$SHAREDIR/browsers" ]]; then 46 | echo -e " ${RED}ERROR:${NRM}${BLD} Missing ${BLU}$SHAREDIR/browsers${NRM}${BLD} - reinstall the package to use profile-sync-daemon.${NRM}" 47 | exit 1 48 | fi 49 | 50 | if [[ $EUID -eq 0 ]]; then 51 | echo -e " ${RED}WARNING:${NRM}${BLD} Do not call ${BLU}$0${NRM}${BLD} as root.${NRM}" 52 | exit 1 53 | fi 54 | 55 | # Create an XDG_RUNTIME_DIR if not given one (i.e. running without DE) 56 | # See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 57 | if [[ -z "$XDG_RUNTIME_DIR" ]]; then 58 | XDG_RUNTIME_DIR="${TMPDIR}/runtime-${user}" 59 | echo -e " ${RED}WARNING:${NRM}${BLD} XDG_RUNTIME_DIR not set, defaulting to '${XDG_RUNTIME_DIR}'.${NRM}" 60 | if [[ ! -d "$XDG_RUNTIME_DIR" ]] && ! mkdir "$XDG_RUNTIME_DIR"; then 61 | echo -e " ${RED}ERROR:${NRM}${BLD} Unable to create runtime directory '${XDG_RUNTIME_DIR}'.${NRM}" 62 | exit 1 63 | fi 64 | if ! chown "${user}" "${XDG_RUNTIME_DIR}"; then 65 | echo -e " ${RED}ERROR:${NRM}${BLD} Unable to make user '${user}' owner of runtime directory '${XDG_RUNTIME_DIR}'.${NRM}" 66 | exit 1 67 | fi 68 | if ! chmod 0700 "${XDG_RUNTIME_DIR}"; then 69 | echo -e " ${RED}ERROR:${NRM}${BLD} Uname to make runtime directory '${XDG_RUNTIME_DIR}' only accessible to user '$user'.${NRM}" 70 | exit 1 71 | fi 72 | elif [[ ! -d "$XDG_RUNTIME_DIR" ]]; then 73 | echo -e " ${RED}ERROR:${NRM}${BLD} Cannot find XDG_RUNTIME_DIR which should be set by systemd.${NRM}" 74 | exit 1 75 | fi 76 | 77 | VOLATILE="$XDG_RUNTIME_DIR/psd" 78 | PID_FILE="$XDG_RUNTIME_DIR/psd.pid" 79 | 80 | # Setup check for config file 81 | if [[ -f "$PSDCONF" ]]; then 82 | if [[ ! -f "$PID_FILE" ]]; then 83 | # do nothing if psd is currently running, otherwise 84 | # make sure only comments and variables/arrays are defined to prevent 85 | # problems like issue #166 86 | if grep -Eqv '^$|^#|^[^ ]*=[^;]*' "$PSDCONF"; then 87 | # something that isn't a blank line, comment, or variable present 88 | # so exit 89 | echo -e " ${RED}ERROR:${NRM}${BLD} Syntax error(s) detected in ${BLU}$PSDCONF${NRM}${BLD} - edit and try again.${NRM}" 90 | echo -e "${NRM}${BLD}Line number: offending comment${NRM}" 91 | grep -Evn '^$|^#|^[^ ]*=[^;]*' "$PSDCONF" 92 | exit 1 93 | fi 94 | fi 95 | . "$PSDCONF" 96 | elif [[ -d "$HOME/.psd" ]]; then 97 | # first check to see if a legacy ~/.psd is present and then move it to the 98 | # new location 99 | mkdir -p "$PSDCONFDIR" 100 | rsync -aX "$HOME/.psd/" "$PSDCONFDIR/" 101 | rm -rf "$HOME/.psd" 102 | echo " The use of $HOME/.psd is deprecated. Existing config has been moved to $PSDCONFDIR" 103 | # source it again retaining any user options 104 | [[ -f "$PSDCONF" ]] && . "$PSDCONF" 105 | else 106 | mkdir -p "$PSDCONFDIR" 107 | if [[ -f "$SHAREDIR/psd.conf" ]]; then 108 | cp "$SHAREDIR/psd.conf" "$PSDCONFDIR" 109 | echo -e " First time running psd so please edit ${BLU}$PSDCONF${NRM}${BLD} to your liking and run again.${NRM}" 110 | exit 0 111 | fi 112 | fi 113 | 114 | # if psd is active, source the snapshot of psd.conf preferentially 115 | # version 6.03 renames this file so if older version is running then 116 | # rotate the old name to the new one 117 | 118 | [[ -f "$PSDCONFDIR/.$user@$(uname -n).pid.conf" ]] && 119 | mv "$PSDCONFDIR/.$user@$(uname -n).pid.conf" "$PSDCONFDIR/.psd.conf" 120 | 121 | if [[ -f "$PID_FILE" ]]; then 122 | if [[ -f "$PSDCONFDIR/.psd.conf" ]]; then 123 | PSDCONF="$PSDCONFDIR/.psd.conf" 124 | unset USE_OVERLAYFS USE_SUSPSYNC BROWSERS USE_BACKUPS BACKUP_LIMIT 125 | . "$PSDCONF" 126 | # defining VOLATILE in the config is deprecated since v6.16 127 | VOLATILE="$XDG_RUNTIME_DIR/psd" 128 | fi 129 | fi 130 | 131 | # define default number of crash-recovery snapshots to save if the user did not 132 | # and check that it is an integer if user did define it 133 | if [[ -z "$BACKUP_LIMIT" ]]; then 134 | BACKUP_LIMIT=5 135 | else 136 | if [[ "$BACKUP_LIMIT" =~ ^[0-9]+$ ]]; then 137 | # correctly setup 138 | true 139 | else 140 | echo -e " ${RED}ERROR:${NRM}${BLD} Bad value for BACKUP_LIMIT detected!${NRM}" 141 | exit 1 142 | fi 143 | fi 144 | 145 | # scope to sync defined in BROWSERS array or from list of supported browsers 146 | if [[ -z "$BROWSERS" ]]; then 147 | mapfile -t BROWSERS < <(find "$SHAREDIR/browsers" -type f -printf "%f\n") 148 | else 149 | if ! declare -p BROWSERS | grep -q 'declare -a'; then 150 | # did not setup as array so redefine it here 151 | IFS=' ' read -r -a BROWSERS <<< "${BROWSERS[@]}" 152 | fi 153 | fi 154 | 155 | # remove duplicate elements if user accidentally polluted array with same entries 156 | # https://stackoverflow.com/questions/13648410/how-can-i-get-unique-values-from-an-array-in-bash 157 | readarray -t BROWSERS < <(printf '%s\n' "${BROWSERS[@]}" | awk '!x[$0]++') 158 | 159 | # simple function to determine user intent rather than using a null value 160 | case "${USE_OVERLAYFS,,}" in 161 | y|yes|true|t|on|1|enabled|enable|use) 162 | OLFS=1 163 | ;; 164 | *) 165 | OLFS=0 166 | ;; 167 | esac 168 | 169 | # simple function to determine user intent rather than using a null value 170 | case "${USE_SUSPSYNC,,}" in 171 | y|yes|true|t|on|1|enabled|enable|use) 172 | SUSPSYNC=1 173 | ;; 174 | *) 175 | SUSPSYNC=0 176 | ;; 177 | esac 178 | 179 | # since the default for this one is a yes, need to force a null value to yes 180 | [[ -z "${USE_BACKUPS,,}" ]] && USE_BACKUPS="yes" 181 | 182 | case "${USE_BACKUPS,,}" in 183 | y|yes|true|t|on|1|enabled|enable|use) 184 | CRRE=1 185 | ;; 186 | *) 187 | CRRE=0 188 | ;; 189 | esac 190 | 191 | # determine if we are using overlayfs (v22 and below) or overlay (v23 and above) 192 | # since mount should call modprobe on invocation, check to see if either 193 | # module is in the tree using modinfo 194 | 195 | if [[ $OLFS -eq 1 ]]; then 196 | # first check to see if either is hardcoded into the kernel 197 | # and of course prefer version 23 198 | [[ $(grep -ciE "overlayfs$" /proc/filesystems) -eq 1 ]] && OLFSVER=22 199 | [[ $(grep -ciE "overlay$" /proc/filesystems) -eq 1 ]] && OLFSVER=23 200 | fi 201 | 202 | if [[ -z $OLFSVER ]]; then 203 | # if neither is hardcoded, see if either module is available 204 | if modinfo overlayfs &>/dev/null; then 205 | OLFSVER=22 206 | fi 207 | 208 | if modinfo overlay &>/dev/null; then 209 | OLFSVER=23 210 | fi 211 | fi 212 | 213 | header() { 214 | echo -e "${BLD}Profile-sync-daemon v$VERS${NRM}" 215 | echo 216 | } 217 | 218 | dep_check() { 219 | # checks for dependencies and that psd.conf is setup correctly 220 | if ! command -v rsync >/dev/null 2>&1; then 221 | echo -e " ${BLD}I require rsync but it's not installed. ${RED}Aborting!${NRM}" 222 | exit 1 223 | fi 224 | if ! command -v modinfo >/dev/null 2>&1; then 225 | echo -e " ${BLD}I require modinfo but it's not installed. ${RED}Aborting!${NRM}" >&2 226 | exit 1 227 | fi 228 | if ! command -v awk >/dev/null 2>&1; then 229 | echo -e " ${BLD}I require awk but it's not installed. ${RED}Aborting!${NRM}" >&2 230 | exit 1 231 | fi 232 | if ! command -v gdbus >/dev/null 2>&1; then 233 | if [[ $SUSPSYNC -eq 1 ]]; then 234 | echo -e " ${BLD}I require gdbus but it's not installed. ${RED}Aborting!${NRM}" 235 | exit 1 236 | fi 237 | fi 238 | if [[ $OLFS -eq 1 ]]; then 239 | [[ $OLFSVER -ge 22 ]] || { 240 | echo -e " ${BLD}Your kernel requires either the ${BLU}overlay${NRM}${BLD} or ${BLU}overlayfs${NRM}${BLD} module to use${NRM}" 241 | echo -e " ${BLD}to use psd's in overlay mode. Cannot find either in your kernel so compile it in and${NRM}" 242 | echo -e " ${BLD}try again or remove the option from ${BLU}$PSDCONF${NRM}${BLD}. ${RED}Aborting!${NRM}" >&2 243 | exit 1 244 | } 245 | fi 246 | 247 | if [[ -f /etc/psd.conf ]]; then 248 | echo -e "${BLD} This version of psd does not support /etc/psd.conf since it runs as your user.${NRM}" 249 | echo -e "${BLD} Recommend that you remove /etc/psd.conf and run it in systemd's user mode:${NRM}" 250 | echo -e "${BLD} systemd --user psd.service${NRM}" 251 | exit 1 252 | fi 253 | } 254 | 255 | config_check() { 256 | if [[ $OLFS -eq 1 ]]; then 257 | # user must have sudo rights to call /usr/bin/mount 258 | # and /usr/bin/umount to use overlay mode 259 | 260 | if ! sudo -kn psd-overlay-helper &>/dev/null; then 261 | FAILCODE=1 262 | fi 263 | 264 | if [[ $FAILCODE -ne 0 ]]; then 265 | echo -e "${BLD}${RED} ERROR!${NRM}${BLD} To use overlayfs mode, $user needs sudo access to ${BLU}/usr/bin/psd-overlay-helper${NRM}${BLD}${NRM}" 266 | echo 267 | echo -e " ${BLD}Add the following line to the end of ${BLU}/etc/sudoers${NRM}${BLD} to enable this functionality:${NRM}" 268 | echo -e " ${BLD}$user ALL=(ALL) NOPASSWD: /usr/bin/psd-overlay-helper${NRM}" 269 | exit 1 270 | fi 271 | fi 272 | 273 | for browser in "${BROWSERS[@]}"; do 274 | if [[ ! -f "$SHAREDIR/browsers/$browser" ]]; then 275 | # user defined an invalid browser 276 | echo -e " ${BLD}${RED}$browser${NRM}${BLD} is not a supported browser. Check config file for typos: ${NRM}${BLU}$PSDCONF${NRM}" 277 | exit 1 278 | fi 279 | done 280 | } 281 | 282 | ungraceful_state_check() { 283 | # if the machine was ungracefully shutdown then the backup will be 284 | # on the filesystem and the link to tmpfs will be on the filesystem 285 | # but the contents will be empty we need to simply remove the link 286 | # and rotate the backup into place 287 | local browser 288 | for browser in "${BROWSERS[@]}"; do 289 | load_env_for "$browser" 290 | for item in "${DIRArr[@]}"; do 291 | DIR="$item" 292 | BACKUP="$item-backup" 293 | BACK_OVFS="$item-back-ovfs" 294 | 295 | # all is well so continue 296 | [[ -e "$DIR/.flagged" ]] && continue 297 | 298 | NOW=$(date +%Y%m%d_%H%M%S) 299 | if [[ -h "$DIR" ]]; then 300 | # symlinked browser profiles are not supported so bail if one is detected 301 | if [[ -d $(readlink "$DIR") ]]; then 302 | echo -e " ${RED}Warning!${NRM}" 303 | echo -e " ${BLD}${BLU}$DIR${NRM}${BLD} appears to be a symlink but these are not supported.${NRM}" 304 | echo -e " ${BLD}Please make the browser profile a live directory and try again. Exiting.${NRM}" 305 | exit 1 306 | else 307 | echo "Ungraceful state detected for $DIR so fixing" 308 | unlink "$DIR" 309 | # refuse to start browser while recovery 310 | ln -s /dev/null "$DIR" 311 | fi 312 | fi 313 | 314 | if [[ -d "$BACKUP" ]]; then 315 | if [[ -d $DIR ]]; then 316 | echo "Unexpected state detected: we have $BACKUP, but $DIR already exists. Trying move $DIR to $DIR" "$DIR-old-profile-$NOW" 317 | mv --no-target-directory "$DIR" "$DIR-old-profile-$NOW" 318 | fi 319 | 320 | if [[ -d "$BACK_OVFS" ]]; then 321 | # always snapshot the most recent of these two dirs... 322 | # if using overlayfs $BACK_OVFS and $BACKUP should be compared 323 | # against each other to see which is newer and then that should 324 | # be what psd snapshots since BACKUP (the lowerdir) is readonly 325 | # at the time the user started psd could be many resync cycles 326 | # in the past 327 | 328 | BACKUP_TIME=$(stat "$BACKUP" | grep Change | awk '{ print $2,$3 }') 329 | BACK_OVFS_TIME=$(stat "$BACK_OVFS" | grep Change | awk '{ print $2,$3 }') 330 | 331 | [[ $(date -d "$BACK_OVFS_TIME" "+%s") -ge $(date -d "$BACKUP_TIME" "+%s") ]] && 332 | TARGETTOKEEP="$BACK_OVFS" || 333 | TARGETTOKEEP="$BACKUP" 334 | 335 | if [[ $CRRE -eq 1 ]]; then 336 | cp -a --reflink=auto "$TARGETTOKEEP" "$BACKUP-crashrecovery-$NOW" 337 | fi 338 | 339 | unlink "$DIR" 340 | mv --no-target-directory "$TARGETTOKEEP" "$DIR" 341 | rm -rf "$BACKUP" 342 | else 343 | # we only find the BACKUP and no BACKOVFS then either the initial resync 344 | # never occurred before the crash using overlayfs or we aren't using overlayfs 345 | # at all which can be treated the same way 346 | 347 | if [[ $CRRE -eq 1 ]]; then 348 | cp -a --reflink=auto "$BACKUP" "$BACKUP-crashrecovery-$NOW" 349 | unlink "$DIR" 350 | mv --no-target-directory "$BACKUP" "$DIR" 351 | fi 352 | fi 353 | fi 354 | 355 | # if overlayfs was active but is no longer, remove $BACK_OVFS 356 | [[ $OLFS -eq 1 ]] || rm -rf "$BACK_OVFS" 357 | done 358 | done 359 | } 360 | 361 | cleanup() { 362 | local browser 363 | for browser in "${BROWSERS[@]}"; do 364 | load_env_for "$browser" 365 | for item in "${DIRArr[@]}"; do 366 | DIR="$item" 367 | 368 | local CRASHArr=() 369 | while IFS= read -d '' -r backup; do 370 | CRASHArr=("${CRASHArr[@]}" "$backup") 371 | done < <(find "${DIR%/*}" -maxdepth 1 -type d -name "${DIR##*/}-backup-crashrecovery-*" -print0 | sort -r -z) 372 | 373 | if [[ ${#CRASHArr[@]} -gt 0 ]]; then 374 | echo -e "${BLD}Deleting ${#CRASHArr[@]} crashrecovery dir(s) for profile ${BLU}$DIR${NRM}" 375 | for backup in "${CRASHArr[@]}"; do 376 | echo -e "${BLD}${RED} $backup${NRM}" 377 | rm -rf "$backup" 378 | done 379 | else 380 | echo -e "${BLD}Found no crashrecovery dirs for: ${BLU}$DIR${NRM}${BLD}${NRM}" 381 | fi 382 | echo 383 | done 384 | done 385 | } 386 | 387 | load_env_for() { 388 | browser="$1" 389 | 390 | homedir=$HOME 391 | group=$(id -g "$user") 392 | 393 | ### Arrays 394 | # profileArr is transient used to store profile paths parsed from 395 | # firefox and aurora 396 | unset profileArr 397 | # DIRArr is a full path corrected for both relative and absolute paths 398 | # reset global variables and arrays 399 | unset DIRArr 400 | 401 | unset PSNAME 402 | . "$SHAREDIR/browsers/$browser" 403 | } 404 | 405 | running_check() { 406 | # check for browsers running and refuse to start if so 407 | # without this cannot guarantee profile integrity 408 | local browser 409 | for browser in "${BROWSERS[@]}"; do 410 | load_env_for "$browser" 411 | [[ -z "$PSNAME" ]] && continue 412 | if pgrep -x -u "$user" "$PSNAME" &>/dev/null; then 413 | echo "Refusing to start; $browser is running by $user!" 414 | exit 1 415 | fi 416 | done 417 | } 418 | 419 | suffix_needed() { 420 | browser=$1 421 | unset check_suffix 422 | . "$SHAREDIR/browsers/$browser" 423 | [[ -n "$check_suffix" ]] 424 | } 425 | 426 | dup_check() { 427 | # only for firefox, icecat, seamonkey, and palemoon 428 | # the LAST directory in the profile MUST be unique 429 | # make sure there are no duplicates in ~/.mozilla//profiles.ini 430 | local browser 431 | for browser in "${BROWSERS[@]}"; do 432 | load_env_for "$browser" 433 | if suffix_needed "$browser"; then 434 | # nothing to check 435 | [[ -z "${DIRArr[*]}" ]] && continue 436 | # browser is on system so check profiles 437 | # 438 | # check that the LAST DIRECTORY in the full path is unique 439 | unique_count=$(printf "%s\n" "${DIRArr[@]##*/}" | sort -u | wc -l) 440 | # no problems so do nothing 441 | [[ ${#DIRArr[@]} -eq $unique_count ]] && continue 442 | 443 | echo -e " ${RED}Error: ${NRM}${BLD}dup profile for ${GRN}$browser${NRM}${BLD} detected. See psd manpage, correct, and try again.${NRM}" 444 | # clip of the 'heftig-' to give correct path 445 | [[ "$browser" = "heftig-aurora" ]] && browser="${browser##*-}" 446 | profile_ini="$homedir/.mozilla/$browser/profiles.ini" 447 | if [[ "$browser" = "palemoon" ]]; then 448 | profile_ini="$homedir/.moonchild productions/pale moon/profiles.ini" 449 | echo -e " ${BLD}Must have unique last directories in ${BLU}${profile_ini}${NRM}${BLD} to use psd.${NRM}" 450 | exit 1 451 | fi 452 | fi 453 | done 454 | } 455 | 456 | kill_browsers() { 457 | # check for browsers running and kill them to safely sync/unsync 458 | # without this cannot guarantee profile integrity 459 | local browser 460 | for browser in "${BROWSERS[@]}"; do 461 | load_env_for "$browser" 462 | 463 | local x=1 464 | while [[ $x -le 60 ]]; do 465 | [[ -n "$PSNAME" ]] || break 466 | pgrep -x -u "$user" "$PSNAME" &>/dev/null || break 467 | 468 | if [[ $x -le 5 ]]; then 469 | pkill -x -SIGTERM -u "$user" "$PSNAME" 470 | else 471 | pkill -x -SIGKILL -u "$user" "$PSNAME" 472 | fi 473 | 474 | x=$(( x + 1 )) 475 | sleep .05 476 | done 477 | done 478 | } 479 | 480 | do_sync_for() { 481 | browser=$1 482 | load_env_for "$browser" 483 | for item in "${DIRArr[@]}"; do 484 | DIR="$item" 485 | BACKUP="$item-backup" 486 | BACK_OVFS="$item-back-ovfs" 487 | suffix= 488 | if suffix_needed "$browser"; then 489 | suffix="-${item##*/}" 490 | fi 491 | TMP="$VOLATILE/$user-$browser$suffix" 492 | UPPER="$VOLATILE/$user-$browser${suffix}-rw" 493 | WORK="$VOLATILE/.$user-$browser${suffix}" 494 | local REPORT 495 | 496 | # make tmpfs container 497 | if [[ -d "$DIR" ]]; then 498 | # retain permissions on sync target 499 | PREFIXP=$(stat -c %a "$DIR") 500 | [[ -r "$TMP" ]] || install -dm"$PREFIXP" --owner="$user" --group="$group" "$TMP" 501 | 502 | if [[ $OLFS -eq 1 ]]; then 503 | if [[ $OLFSVER -eq 23 ]]; then 504 | [[ -r "$UPPER" ]] || install -dm"$PREFIXP" --owner="$user" --group="$group" "$UPPER" 505 | [[ -r "$WORK" ]] || install -dm"$PREFIXP" --owner="$user" --group="$group" "$WORK" 506 | elif [[ $OLFSVER -eq 22 ]]; then 507 | [[ -r "$UPPER" ]] || install -dm"$PREFIXP" --owner="$user" --group="$group" "$UPPER" 508 | fi 509 | fi 510 | 511 | # backup target and link to tmpfs container 512 | if [[ $(readlink "$DIR") != "$TMP" ]]; then 513 | mv --no-target-directory "$DIR" "$BACKUP" 514 | # refuse to start browser while initial sync 515 | ln -s /dev/null "$DIR" 516 | fi 517 | 518 | # sync the tmpfs targets to the disc 519 | if [[ -e "$DIR"/.flagged ]]; then 520 | REPORT="resync" 521 | if [[ $OLFS -eq 1 ]]; then 522 | rsync -aX --delete-after --inplace --no-whole-file --exclude .flagged "$DIR/" "$BACK_OVFS/" 523 | else 524 | rsync -aX --delete-after --inplace --no-whole-file --exclude .flagged "$DIR/" "$BACKUP/" 525 | fi 526 | else 527 | # initial sync 528 | REPORT="sync" 529 | if [[ $OLFS -eq 1 ]]; then 530 | if ! sudo psd-overlay-helper -v "$OLFSVER" -l "$BACKUP" -u "$UPPER" -w "$WORK" -d "$TMP" mountup; then 531 | echo -e "Error in trying to mount $TMP - this should not happen!" 532 | exit 1 533 | fi 534 | else 535 | # keep user from launching browser while rsync is active 536 | rsync -aX --inplace --no-whole-file "$BACKUP/" "$TMP" 537 | fi 538 | 539 | # now browser can start 540 | [[ $(readlink "$DIR") = "/dev/null" ]] && unlink "$DIR" 541 | ln -s "$TMP" "$DIR" 542 | chown -h "$user":"$group" "$DIR" 543 | touch "$DIR/.flagged" 544 | fi 545 | echo -e "${BLD}$browser $REPORT successful${NRM}" 546 | else 547 | if [[ ! -d "$homedir" ]] ; then 548 | echo -e "${RED}$DIR does not exist! Is /home unmounted?${NRM}" >&2 549 | exit 1 550 | elif [[ -d "$BACKUP" ]] ; then 551 | echo -e "${RED}$DIR does not exist or is a broken symlink! Is $VOLATILE unmounted?${NRM}" >&2 552 | exit 1 553 | fi 554 | fi 555 | done 556 | } 557 | 558 | do_sync() { 559 | touch "$PID_FILE" 560 | 561 | # make a snapshot of psd.conf and redefine its location to this snapshot 562 | # while psd is running to keep any edits made to the "live" psd.conf from 563 | # potentially orphaning the snapshot copies thus preserving the data 564 | 565 | if [[ ! -f "$PSDCONFDIR/.psd.conf" ]]; then 566 | { 567 | echo "# Automatically generated file; DO NOT EDIT!" 568 | echo "# The purpose is to snapshot the settings used when psd was activated." 569 | echo "# Any edits to the live config: $PSDCONFDIR/psd.conf" 570 | echo "# will be applied the _next_ time psd is activated." 571 | echo "#" 572 | echo "USE_OVERLAYFS=\"$USE_OVERLAYFS\"" 573 | echo "USE_SUSPSYNC=\"$USE_SUSPSYNC\"" 574 | echo "BROWSERS=\"${BROWSERS[*]}\"" 575 | echo "USE_BACKUPS=\"$USE_BACKUPS\"" 576 | echo "BACKUP_LIMIT=\"$BACKUP_LIMIT\"" 577 | } >> "$PSDCONFDIR/.psd.conf" 578 | chmod 400 "$PSDCONFDIR/.psd.conf" 579 | fi 580 | 581 | local browser 582 | for browser in "${BROWSERS[@]}"; do 583 | do_sync_for "$browser" 584 | done 585 | } 586 | 587 | enforce() { 588 | local browser 589 | for browser in "${BROWSERS[@]}"; do 590 | local CRASHArr=() 591 | while IFS= read -d '' -r backup; do 592 | CRASHArr=("${CRASHArr[@]}" "$backup") 593 | done < <(find "${DIR%/*}" -maxdepth 1 -type d -name "${DIR##*/}-backup-crashrecovery-*" -print0 | sort -r -z) 594 | 595 | if [[ ${#CRASHArr[@]} -gt $BACKUP_LIMIT ]]; then 596 | for remove in "${CRASHArr[@]:$BACKUP_LIMIT}"; do 597 | rm -rf "$remove" 598 | done 599 | fi 600 | done 601 | } 602 | 603 | do_unsync() { 604 | rm -f "$PID_FILE" "$PSDCONFDIR/.psd.conf" 605 | 606 | local browser 607 | for browser in "${BROWSERS[@]}"; do 608 | load_env_for "$browser" 609 | for item in "${DIRArr[@]}"; do 610 | DIR="$item" 611 | BACKUP="$item-backup" 612 | BACK_OVFS="$item-back-ovfs" 613 | suffix= 614 | if suffix_needed "$browser"; then 615 | suffix="-${item##*/}" 616 | fi 617 | TMP="$VOLATILE/$user-$browser$suffix" 618 | UPPER="$VOLATILE/$user-$browser${suffix}-rw" 619 | WORK="$VOLATILE/.$user-$browser${suffix}" 620 | # check if user has browser profile 621 | if [[ -h "$DIR" ]]; then 622 | unlink "$DIR" 623 | # this assumes that the backup is always updated so 624 | # be sure to invoke a sync before an unsync 625 | # 626 | # restore original dirtree 627 | [[ -d "$BACKUP" ]] && mv --no-target-directory "$BACKUP" "$DIR" 628 | if [[ $OLFS -eq 1 ]] && mountpoint -q "$TMP"; then 629 | rsync -aX --delete-after --inplace --no-whole-file --exclude .flagged "$BACK_OVFS/" "$DIR/" 630 | sudo psd-overlay-helper -d "$TMP" -w "$WORK" mountdown && rm -rf "$TMP" "$UPPER" 631 | fi 632 | [[ -d "$TMP" ]] && rm -rf "$TMP" 633 | echo -e "${BLD}$browser unsync successful${NRM}" 634 | else 635 | if [[ ! -d "$homedir" ]] ; then 636 | echo -e "${RED}$DIR does not exist! Is /home unmounted?${NRM}" >&2 637 | exit 1 638 | fi 639 | fi 640 | done 641 | done 642 | } 643 | 644 | parse() { 645 | psd_state=$(systemctl --user is-active psd) 646 | resync_state=$(systemctl --user is-active psd-resync.timer) 647 | psd_suspend_sync_state=$(pgrep -cf "psd-suspend-sync") 648 | if [[ "$psd_suspend_sync_state" != 0 ]]; then 649 | psss_state="enabled" 650 | else 651 | psss_state="disabled" 652 | fi 653 | if [[ $OLFS -eq 1 ]]; then 654 | olfs_color="${GRN}" 655 | ofls_state="enabled" 656 | else 657 | olfs_color="${RED}" 658 | ofls_state="disabled" 659 | fi 660 | [[ "$psd_state" = "active" ]] && psd_color="${GRN}" || psd_color="${RED}" 661 | [[ "$resync_state" = "active" ]] && resync_color="${GRN}" || resync_color="${RED}" 662 | [[ "$psd_suspend_sync_state" != 0 ]] && psss_color="${GRN}" || psss_color="${RED}" 663 | echo -en " ${BLD}systemd service:" 664 | echo -e "$(tput cr)$(tput cuf 17) ${psd_color}$psd_state${NRM}${BLD}${NRM}" 665 | echo -en " ${BLD}resync-timer:" 666 | echo -e "$(tput cr)$(tput cuf 17) ${resync_color}$resync_state${NRM}${BLD}${NRM}" 667 | echo -en " ${BLD}sync on sleep:" 668 | echo -e "$(tput cr)$(tput cuf 17) ${psss_color}$psss_state${NRM}${BLD}${NRM}" 669 | echo -en " ${BLD}use overlayfs:" 670 | echo -e "$(tput cr)$(tput cuf 17) ${olfs_color}$ofls_state${NRM}${BLD}${NRM}" 671 | echo 672 | echo -e "${BLD}Psd will manage the following per ${BLU}${PSDCONF}${NRM}${BLD}:${NRM}" 673 | echo 674 | local browser 675 | for browser in "${BROWSERS[@]}"; do 676 | load_env_for "$browser" 677 | for item in "${DIRArr[@]}"; do 678 | DIR="$item" 679 | BACKUP="$item-backup" 680 | suffix= 681 | if suffix_needed "$browser"; then 682 | suffix="-${item##*/}" 683 | fi 684 | UPPER="$VOLATILE/$user-$browser${suffix}-rw" 685 | if [[ -d "$DIR" ]]; then 686 | local CRASHArr=() 687 | while IFS= read -d '' -r backup; do 688 | CRASHArr=("${CRASHArr[@]}" "$backup") 689 | done < <(find "${DIR%/*}" -maxdepth 1 -type d -name "${DIR##*/}-backup-crashrecovery-*" -print0 | sort -r -z) 690 | 691 | # get permissions on profile dir and be smart about it since symlinks are all 777 692 | [[ -f $PID_FILE ]] && TRUEP=$(stat -c %a "$BACKUP") || TRUEP=$(stat -c %a "$DIR") 693 | # since $XDG_RUNTIME_DIR is 700 by default so pass on by 694 | if [[ "$VOLATILE" = "$XDG_RUNTIME_DIR" ]]; then 695 | warn= 696 | else 697 | # using something other than $XDG_RUNTIME_DIR so check for privacy 698 | [[ $TRUEP -ne 700 ]] && warn=1 699 | fi 700 | # profile dir size 701 | psize=$(du -Dh --max-depth=0 "$DIR" 2>/dev/null | awk '{ print $1 }') 702 | echo -en " ${BLD}browser/psname:" 703 | echo -e "$(tput cr)$(tput cuf 17) $browser/$PSNAME${NRM}" 704 | echo -en " ${BLD}owner/group id:" 705 | echo -e "$(tput cr)$(tput cuf 17) $user/$group${NRM}" 706 | echo -en " ${BLD}sync target:" 707 | echo -e "$(tput cr)$(tput cuf 17) ${BLU}$DIR${NRM}" 708 | if [[ $warn -eq 1 ]]; then 709 | echo -e "$(tput cr)$(tput cuf 17) ${RED} Permissions are $TRUEP on this profile.${NRM}" 710 | echo -e "$(tput cr)$(tput cuf 17) ${RED} Recommend a setting of 700 for increased privacy!${NRM}" 711 | warn= 712 | fi 713 | echo -en " ${BLD}tmpfs dir:" 714 | echo -e "$(tput cr)$(tput cuf 17) ${GRN}$VOLATILE/$user-$browser$suffix${NRM}" 715 | echo -en " ${BLD}profile size:" 716 | echo -e "$(tput cr)$(tput cuf 17) $psize${NRM}" 717 | if [[ $OLFS -eq 1 ]]; then 718 | rwsize=$(du -Dh --max-depth=0 "$UPPER" 2>/dev/null | awk '{ print $1 }') 719 | echo -en " ${BLD}overlayfs size:" 720 | echo -e "$(tput cr)$(tput cuf 17) $rwsize${NRM}" 721 | fi 722 | if [[ $BACKUP_LIMIT -ne 5 ]]; then 723 | # only print if not the hardcoded default 724 | echo -en " ${BLD}backup limit:" 725 | echo -e "$(tput cr)$(tput cuf 17) $BACKUP_LIMIT${NRM}" 726 | fi 727 | echo -en " ${BLD}recovery dirs:" 728 | if [[ "${#CRASHArr[@]}" -eq 0 ]]; then 729 | echo -e "$(tput cr)$(tput cuf 17) none${NRM}" 730 | else 731 | echo -e "$(tput cr)$(tput cuf 17) ${RED}${#CRASHArr[@]}${NRM}${BLD} <- delete with the c option${NRM}" 732 | for backup in "${CRASHArr[@]}"; do 733 | psize=$(du -Dh --max-depth=0 "$backup" 2>/dev/null | awk '{ print $1 }') 734 | echo -en " ${BLD} dir path/size:" 735 | echo -e "$(tput cr)$(tput cuf 17) ${BLU}$backup ${NRM}${BLD}($psize)${NRM}" 736 | done 737 | fi 738 | echo 739 | fi 740 | done 741 | done 742 | } 743 | 744 | take_inhibit_lock() { 745 | # ensure we only take one lock at a time 746 | release_inhibit_lock 747 | 748 | # background this to avoid hanging on startup 749 | /usr/bin/psd-suspend-sync & 750 | } 751 | 752 | release_inhibit_lock() { 753 | [[ "$(pgrep -cf "psd-suspend-sync")" != 0 ]] && pkill -f psd-suspend-sync 754 | } 755 | 756 | case "$1" in 757 | p|P|Parse|parse|Preview|preview|debug) 758 | dep_check 759 | config_check 760 | dup_check 761 | ungraceful_state_check 762 | header 763 | parse 764 | ;; 765 | c|C|clean|Clean) 766 | dep_check 767 | config_check 768 | dup_check 769 | header 770 | cleanup 771 | ;; 772 | startup) 773 | # target for psd.service's ExecStart= for consistent error handling 774 | if [[ ! -f $PID_FILE ]]; then 775 | dep_check 776 | config_check 777 | dup_check 778 | running_check 779 | ungraceful_state_check 780 | [[ $SUSPSYNC -eq 1 ]] && take_inhibit_lock 781 | echo -e "${BLD}psd startup check successful${NRM}" 782 | fi 783 | ;; 784 | suspend-sync) 785 | if [[ -f $PID_FILE ]]; then 786 | # system preparing for sleep mode, resync when psd is active 787 | do_sync 788 | fi 789 | ;; 790 | recycle-inhibit-lock) 791 | # take inhibit lock for next suspend cycle 792 | take_inhibit_lock 793 | ;; 794 | sync|resync) 795 | if [[ -f $PID_FILE ]]; then 796 | do_sync 797 | else 798 | dep_check 799 | config_check 800 | dup_check 801 | running_check 802 | ungraceful_state_check 803 | do_sync 804 | enforce 805 | fi 806 | ;; 807 | unsync) 808 | if [[ -f $PID_FILE ]]; then 809 | do_sync 810 | kill_browsers 811 | do_unsync 812 | [[ $SUSPSYNC -eq 1 ]] && release_inhibit_lock 813 | fi 814 | ;; 815 | *) 816 | header 817 | echo -e " ${BLD}$0 ${NRM}${GRN}[option]${NRM}" 818 | echo -e " ${BLD} ${NRM}${GRN}preview${NRM}${BLD} Parse config file (${NRM}${BLU}${PSDCONF}${NRM}${BLD}) to see which profiles will be managed.${NRM}" 819 | echo -e " ${BLD} ${NRM}${GRN}clean${NRM}${BLD} Clean (delete without prompting) ALL crashrecovery dirs for all profiles.${NRM}" 820 | echo 821 | echo -e " ${BLD}It is ${RED}HIGHLY DISCOURAGED${NRM}${BLD} to directly call $0 to sync, resync, or to unsync.${NRM}" 822 | echo 823 | if [[ -f /usr/lib/systemd/user/psd.service ]]; then 824 | echo -e " ${BLD}Instead, use systemd to start/stop profile-sync-daemon.${NRM}" 825 | echo 826 | echo -e " ${BLD}systemctl --user ${NRM}${GRN}[option]${NRM}${BLD} psd${NRM}" 827 | echo -e " ${BLD} ${NRM}${GRN}start${NRM}${BLD} Turn on daemon; make symlinks and actively manage targets in tmpfs.${NRM}" 828 | echo -e " ${BLD} ${NRM}${GRN}stop${NRM}${BLD} Turn off daemon; remove symlinks and rotate tmpfs data back to disc.${NRM}" 829 | echo -e " ${BLD} ${NRM}${GRN}enable${NRM}${BLD} Autostart daemon when system comes up.${NRM}" 830 | echo -e " ${BLD} ${NRM}${GRN}disable${NRM}${BLD} Remove daemon from the list of autostart daemons.${NRM}" 831 | elif [[ -f /etc/init.d/psd ]]; then 832 | echo -e " ${BLD}Instead, use the init system to start/stop profile-sync-daemon.${NRM}" 833 | echo 834 | echo -e " ${BLD}sudo service psd ${NRM}${GRN}[option]${NRM}${BLD} or /etc/init.d/psd ${NRM}${GRN}[option]${NRM}" 835 | echo -e " ${BLD} ${NRM}${GRN}start${NRM}${BLD} Turn on daemon; make symlinks and actively manage targets in tmpfs.${NRM}" 836 | echo -e " ${BLD} ${NRM}${GRN}stop${NRM}${BLD} Turn off daemon; remove symlinks and rotate tmpfs data back to disc.${NRM}" 837 | fi 838 | ;; 839 | esac 840 | exit 0 841 | 842 | # vim:set ts=2 sw=2 et: 843 | -------------------------------------------------------------------------------- /common/psd-overlay-helper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | readonly PATH=/usr/bin:/bin 3 | readonly IFS=$' \t\n' 4 | 5 | while getopts :v:l:u:w:d: OPT; do 6 | case $OPT in 7 | v) 8 | declare -ir OLFSVER=$OPTARG 9 | ;; 10 | l) 11 | readonly BACKUP=$OPTARG 12 | ;; 13 | u) 14 | readonly UPPER=$OPTARG 15 | ;; 16 | w) 17 | readonly WORK=$OPTARG 18 | ;; 19 | d) 20 | readonly TMP=$OPTARG 21 | ;; 22 | *) 23 | exit 1 24 | ;; 25 | esac 26 | done 27 | shift $(( OPTIND - 1 )) 28 | OPTIND=1 29 | 30 | ## TODO - pass error codes back to psd so it can break if the mount command fails 31 | case "$1" in 32 | mountup) 33 | # write access to upper/workdir is required or do not overlay lowerdirs 34 | user=$(stat -c %U "$TMP") 35 | if ! sudo -u "$user" test -w "$BACKUP"; then 36 | echo "User $user has no write permissions for $BACKUP. Aborting..." >&2 37 | exit 1 38 | fi 39 | 40 | user=$(stat -c %U "$UPPER") 41 | if ! sudo -u "$user" test -w "$BACKUP"; then 42 | echo "User $user has no write permissions for $BACKUP. Aborting..." >&2 43 | exit 1 44 | fi 45 | if [[ $OLFSVER -eq 23 ]]; then 46 | mount -o nosuid,nodev -t overlay overlaid -olowerdir="$BACKUP",upperdir="$UPPER",workdir="$WORK" "$TMP" 47 | elif [[ $OLFSVER -eq 22 ]]; then 48 | mount -o nosuid,nodev -t overlayfs overlaid -olowerdir="$BACKUP",upperdir="$UPPER" "$TMP" 49 | fi 50 | ;; 51 | mountdown) 52 | umount "$TMP" && rm -rf "$WORK" 53 | ;; 54 | *) 55 | echo "Do not call this script directly; psd will do so for you. Thank you, come again." 56 | exit 0 57 | ;; 58 | esac 59 | 60 | # vim:set ts=2 sw=2 et: 61 | -------------------------------------------------------------------------------- /common/psd-suspend-sync: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dbus_interface="org.freedesktop.login1" 4 | dbus_member="PrepareForSleep" 5 | 6 | # system suspends when 'PrepareForSleep' signal is 'true': 7 | # ... /org/freedesktop/login1: org.freedesktop.login1.Manager.PrepareForSleep (true,) ... 8 | # system resumes when 'PrepareForSleep' signal is 'false' 9 | # ... /org/freedesktop/login1: org.freedesktop.login1.Manager.PrepareForSleep (false,) ... 10 | dbus_process_sleep() { 11 | local line 12 | while read -r line; do 13 | if [[ "$line" =~ $dbus_member ]]; then 14 | if [[ "$line" =~ 'true' ]]; then 15 | ### SUSPEND ### 16 | logger '[psd-suspend-sync] Issuing suspend-sync request...' 17 | /usr/bin/profile-sync-daemon suspend-sync 18 | # the lock will be released now 19 | break 20 | elif [[ "$line" =~ 'false' ]]; then 21 | ### RESUME ### 22 | logger '[psd-suspend-sync] re-taking inhibit lock...' 23 | /usr/bin/profile-sync-daemon recycle-inhibit-lock 24 | break 25 | fi 26 | fi 27 | done 28 | } 29 | 30 | exec {gdbus_fd}< <(gdbus monitor --system --dest "$dbus_interface") 31 | gdbus_PID=$! 32 | trap 'exec {gdbus_fd}<&-; kill "$gdbus_PID"' EXIT 33 | 34 | { 35 | # delay sleep until browser profiles are written to disk 36 | systemd-inhibit --mode="delay" --what="sleep" \ 37 | --who="profile-sync-daemon" --why="psd resync on suspend" \ 38 | cat | dbus_process_sleep 39 | 40 | # detect resume and restart the entire process 41 | dbus_process_sleep 42 | } <&$gdbus_fd 43 | 44 | # vim:set ts=2 sw=2 et: 45 | -------------------------------------------------------------------------------- /common/psd.conf: -------------------------------------------------------------------------------- 1 | # 2 | # $XDG_CONFIG_HOME/psd/psd.conf 3 | # 4 | # For documentation, refer man 1 psd or to the wiki page 5 | # https://wiki.archlinux.org/index.php/Profile-sync-daemon 6 | 7 | ## NOTE the following: 8 | ## To protect data from corruption, in the event that you do make an edit while 9 | ## psd is active, any changes made will be applied the next time you start psd. 10 | 11 | # Uncomment and set to "yes" to use overlayfs instead of a full copy to reduce 12 | # the memory costs and to improve sync/unsync operations. Note that your kernel 13 | # MUST have this module available in order to use this mode. 14 | # 15 | #USE_OVERLAYFS="no" 16 | 17 | # Uncomment and set to "yes" to resync on suspend to reduce potential data loss. 18 | # Note that your system MUST have gdbus from glib2 installed to use this mode. 19 | # 20 | #USE_SUSPSYNC="no" 21 | 22 | # List any browsers in the array below to have managed by psd. Useful if you do 23 | # not wish to have all possible browser profiles managed which is the default if 24 | # this array is left commented. 25 | # 26 | # Possible values: 27 | # chromium 28 | # chromium-dev 29 | # conkeror.mozdev.org 30 | # epiphany 31 | # falkon 32 | # firefox 33 | # firefox-trunk 34 | # google-chrome 35 | # google-chrome-beta 36 | # google-chrome-unstable 37 | # heftig-aurora 38 | # icecat 39 | # inox 40 | # luakit 41 | # midori 42 | # opera 43 | # opera-beta 44 | # opera-developer 45 | # opera-legacy 46 | # otter-browser 47 | # qupzilla 48 | # qutebrowser 49 | # palemoon 50 | # rekonq 51 | # seamonkey 52 | # surf 53 | # vivaldi 54 | # vivaldi-snapshot 55 | # 56 | #BROWSERS=() 57 | 58 | # Uncomment and set to "no" to completely disable the crash recovery feature. 59 | # 60 | # The default is to create crash recovery backups if the system is ungracefully 61 | # powered-down due to a kernel panic, hitting the reset switch, battery going 62 | # dead, etc. Some users keep very diligent backups and don't care to have this 63 | # feature enabled. 64 | #USE_BACKUPS="yes" 65 | 66 | # Uncomment and set to an integer that is the maximum number of crash recovery 67 | # snapshots to keep (the oldest ones are deleted first). 68 | # 69 | # The default is to save the most recent 5 crash recovery snapshots. 70 | #BACKUP_LIMIT=5 71 | -------------------------------------------------------------------------------- /common/zsh-completion: -------------------------------------------------------------------------------- 1 | #compdef psd profile-sync-daemon 2 | 3 | _psd() { 4 | local -a options 5 | 6 | options=('p:Preview what psd will do/is doing and printout useful info' 7 | 'c:Clean (delete without prompting) ALL crashrecovery dirs for all profiles') 8 | 9 | _describe 'options' options 10 | } 11 | 12 | _psd 13 | -------------------------------------------------------------------------------- /contrib/brave: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/BraveSoftware/Brave-Browser" 2 | PSNAME="brave" 3 | -------------------------------------------------------------------------------- /contrib/floorp: -------------------------------------------------------------------------------- 1 | if [[ -d "$HOME"/.floorp ]]; then 2 | index=0 3 | PSNAME="$browser" 4 | while read -r profileItem; do 5 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 6 | # path is not relative 7 | DIRArr[$index]="$profileItem" 8 | else 9 | # we need to append the default path to give a 10 | # fully qualified path 11 | DIRArr[$index]="$HOME/.floorp/$profileItem" 12 | fi 13 | (( index=index+1 )) 14 | done < <(grep '[Pp]'ath= "$HOME"/.floorp/profiles.ini | sed 's/[Pp]ath=//') 15 | fi 16 | 17 | check_suffix=1 18 | -------------------------------------------------------------------------------- /contrib/microsoft-edge: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /contrib/microsoft-edge-beta: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /contrib/thorium: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/$browser" 2 | PSNAME="$browser" 3 | -------------------------------------------------------------------------------- /contrib/vscode: -------------------------------------------------------------------------------- 1 | DIRArr[0]="$XDG_CONFIG_HOME/Code" 2 | PSNAME="vscode" 3 | -------------------------------------------------------------------------------- /contrib/zen: -------------------------------------------------------------------------------- 1 | if [[ -d "$HOME"/.zen ]]; then 2 | index=0 3 | PSNAME="$browser" 4 | while read -r profileItem; do 5 | if [[ $(echo "$profileItem" | cut -c1) = "/" ]]; then 6 | # path is not relative 7 | DIRArr[$index]="$profileItem" 8 | else 9 | # we need to append the default path to give a 10 | # fully qualified path 11 | DIRArr[$index]="$HOME/.zen/$profileItem" 12 | fi 13 | (( index=index+1 )) 14 | done < <(grep '[Pp]'ath= "$HOME"/.zen/profiles.ini | sed 's/[Pp]ath=//') 15 | fi 16 | 17 | check_suffix=1 18 | -------------------------------------------------------------------------------- /doc/psd-overlay-helper.1: -------------------------------------------------------------------------------- 1 | .TH psd-overlay-helper 1 "13 June 2016" "" "" 2 | .SH NAME 3 | \fBpsd-overlay-helper \fP- Script to use overlay file system for profile-sync-daemon. 4 | \fB 5 | .SH DESCRIPTION 6 | Profile-sync-daemon (psd) is a tiny pseudo-daemon designed to manage browser profile/profiles in tmpfs and to periodically sync back to the physical disc (HDD/SSD). This is accomplished by an innovative use of rsync to maintain synchronization between a tmpfs copy and media-bound backup of the browser profile/profiles. Additionally, psd features several crash recovery features. 7 | 8 | The psd-overlay-helper script is used internally to enable the usage of the overlay file system. It should not be called by the user directly. 9 | .SH CONTRIBUTE 10 | Users wishing to contribute to this project should fork it and send a pull request. Source is freely available on the project page linked below. 11 | .SH ONLINE 12 | .IP \(bu 3 13 | Project page: https://github.com/graysky2/profile-sync-daemon 14 | .IP \(bu 3 15 | Wiki page: https://wiki.archlinux.org/index.php/Profile-sync-daemon 16 | .SH AUTHOR 17 | graysky (graysky AT archlinux DOT us) 18 | -------------------------------------------------------------------------------- /doc/psd.1: -------------------------------------------------------------------------------- 1 | .\" Text automatically generated by txt2man 2 | .TH profile-sync-daemon 1 "02 October 2023" "" "" 3 | .SH NAME 4 | \fBprofile-sync-daemon \fP- Symlinks and syncs browser profiles to RAM (tmpfs) thus reducing HDD/SSD calls and speeding up browsers. 5 | \fB 6 | .SH DESCRIPTION 7 | Profile-sync-daemon (psd) is a tiny pseudo-daemon designed to manage browser profile/profiles in tmpfs and to periodically sync back to the physical disc (HDD/SSD). This is accomplished by an innovative use of rsync to maintain synchronization between a tmpfs copy and media-bound backup of the browser profile/profiles. Additionally, psd features several crash-recovery features. 8 | .PP 9 | Design goals of psd: 10 | .RS 11 | .IP \(bu 3 12 | Completely transparent user experience. 13 | .IP \(bu 3 14 | Reduced wear to physical discs (particularly SSDs). 15 | .IP \(bu 3 16 | Speed. 17 | .RE 18 | .PP 19 | Since the profile/profiles, browser cache*, etc. are relocated into tmpfs (RAM disk), the corresponding I/O associated with using the browser is also redirected from the physical disc to the RAM, thus reducing wear to the physical disc and improving browser responsiveness. 20 | .PP 21 | *Note that some browsers such as Chrome/Chromium, Firefox (since v21), Midori, and Rekonq actually keep their cache directories separate from their browser profile directory. It is not within the scope of profile-sync-daemon to modify this behavior; users wishing to relocate this directory, may refer to the following url for several work-arounds: https://wiki.archlinux.org/index.php/Chromium_Tips_and_Tweaks#Cache_in_tmpfs 22 | .SH SETUP 23 | $XDG_CONFIG_HOME/psd/psd.conf (referred to hereafter as "the config file") contains all user managed settings. 24 | .PP 25 | NOTE: edits made to the config file while psd is active will be applied only after the service has been restarted. 26 | .RS 27 | .IP \(bu 3 28 | Optionally enable the use of overlayfs to improve sync speed and to use a smaller memory footprint. Do this in the USE_OVERLAYFS variable. The user will require no password sudo rights to /usr/bin/psd-overlay-helper to use this option and the kernel must support overlayfs version 22 or higher. See the FAQ below for additional details. 29 | .IP \(bu 3 30 | Optionally have psd resync to the filesystem prior to a sleep call. This can help in the event that the system does not properly wake up. Do this in the USE_SUSPSYNC variable. 31 | .IP \(bu 3 32 | Optionally define which browsers are to be managed in the BROWSERS array. If none are defined, the default is all detected browsers. 33 | .IP \(bu 3 34 | Optionally disable the use of crash-recovery snapshots (not recommended). Do this in the USE_BACKUPS variable. 35 | .IP \(bu 3 36 | Optionally define the number of crash-recovery snapshots to keep. Do this in the BACKUP_LIMIT variable. 37 | .RE 38 | .PP 39 | NOTE: occasionally, updates/changes are made to the default config file (/usr/share/psd/psd.conf) upstream. The user copy ($XDG_CONFIG_HOME/psd/psd.conf) will need to be diffed against it. 40 | .SH RUNNING PSD 41 | .SS PREVIEW MODE 42 | The preview option can be called to show users exactly what psd will do/is doing based on the entries in the config file. It will also provide useful information such as profile size, paths, and if any recovery snapshots have been created. 43 | .PP 44 | .nf 45 | .fam C 46 | $ psd p 47 | 48 | Profile-sync-daemon v6.39 49 | 50 | systemd service: active 51 | resync-timer: active 52 | sync on sleep: enabled 53 | use overlayfs: enabled 54 | 55 | Psd will manage the following per /home/facade/.config/psd/.psd.conf settings: 56 | 57 | browser/psname: chromium/chromium 58 | owner/group id: facade/100 59 | sync target: /home/facade/.config/chromium 60 | tmpfs dir: /run/user/1000/facade-chromium 61 | profile size: 93M 62 | overlayfs size: 39M 63 | recovery dirs: 2 <- delete with the c option 64 | dir path/size: /home/facade/.config/chromium-backup-crashrecovery-20200423_171359 (92M) 65 | dir path/size: /home/facade/.config/chromium-backup-crashrecovery-20200424_112204 (93M) 66 | 67 | browser/psname: firefox/firefox 68 | owner/group id: facade/100 69 | sync target: /home/facade/.mozilla/firefox/f8cv8bfu.default 70 | tmpfs dir: /run/user/1000/facade-firefox-f8cv8bfu.default 71 | 72 | profile size: 145M 73 | overlayfs size: 13M 74 | recovery dirs: none 75 | 76 | .fam T 77 | .fi 78 | .SS START AND STOP PSD 79 | Psd ships with a systemd user service to start or stop it (psd.service). Additionally, a provided resync-timer will run an hourly resync from tmpfs back to the disk. The resync-timer is started automatically with psd.service so there is no need to start the timer; only start psd.service. 80 | .PP 81 | .nf 82 | .fam C 83 | $ systemctl --user [option] psd.service 84 | 85 | .fam T 86 | .fi 87 | Available options: 88 | start 89 | stop 90 | enable 91 | disable 92 | .SS CLEAN MODE 93 | The clean mode will delete ALL recovery snapshots that have accumulated. Only run it when sure these are no longer needed. 94 | .PP 95 | .nf 96 | .fam C 97 | $ psd c 98 | 99 | Profile-sync-daemon v6.39 100 | 101 | Deleting 2 crashrecovery dirs for profile /home/facade/.config/chromium 102 | /home/facade/.config/chromium-backup-crashrecovery-20200423_171359 103 | /home/facade/.config/chromium-backup-crashrecovery-20200424_112204 104 | 105 | .fam T 106 | .fi 107 | .SH SUPPORTED BROWSERS 108 | .IP \(bu 3 109 | Chromium (stable, beta, and dev) 110 | .IP \(bu 3 111 | Conkeror 112 | .IP \(bu 3 113 | Epiphany 114 | .IP \(bu 3 115 | Falkon 116 | .IP \(bu 3 117 | Firefox (stable, beta, and aurora) 118 | .IP \(bu 3 119 | Firefox-trunk (this is an Ubuntu-only browser: http://www.webupd8.org/2011/05/install-firefox-nightly-from-ubuntu-ppa.html) 120 | .IP \(bu 3 121 | Google Chrome (stable, beta, and dev) 122 | .IP \(bu 3 123 | Heftig's version of Aurora (Arch Linux: https://bbs.archlinux.org/viewtopic.php?id=117157) 124 | .IP \(bu 3 125 | Icecat 126 | .IP \(bu 3 127 | Iceweasel 128 | .IP \(bu 3 129 | Inox (https://bbs.archlinux.org/viewtopic.php?id=198763) 130 | .IP \(bu 3 131 | Luakit 132 | .IP \(bu 3 133 | Midori 134 | .IP \(bu 3 135 | Opera (legacy, stable, next, and developer) 136 | .IP \(bu 3 137 | Otter-browser 138 | .IP \(bu 3 139 | Palemoon 140 | .IP \(bu 3 141 | QupZilla 142 | .IP \(bu 3 143 | Qutebrowser 144 | .IP \(bu 3 145 | Rekonq 146 | .IP \(bu 3 147 | Seamonkey 148 | .IP \(bu 3 149 | Vivaldi 150 | .IP \(bu 3 151 | Vivaldi-snapshot 152 | .RE 153 | .PP 154 | Psd's infrastructure can work in principal with any browser that uses a generic chrome or mozilla, etc. format. User supplied profiles are provided in /usr/share/psd/contrib/ and can be manually copied to /usr/share/psd/browsers/ if one wishes to sync that particular browser. Make a corresponding entry in the BROWSERS array within the config file. Support for these is unsupported. 155 | .SH NOTE ON SYMLINKED PROFILES 156 | Currently, psd does not support symlinked profiles and will refuse to sync if one is detected. For example, your firefox profile is ~/.mozilla/firefox/f8cv8bfu.default but you have moved that directory to /foo/bar/f8cv8bfu.default and replaced it with symlink: 157 | .PP 158 | .nf 159 | .fam C 160 | $ ls -l ~/.mozilla/firefox 161 | lrwxrwxrwx 1 facade users 26 Oct 1 17:02 f8cv8bfu.default -> /foo/bar/f8cv8bfu.default 162 | 163 | .fam T 164 | .fi 165 | Running psd in preview mode will end in an error informing you of this: 166 | .PP 167 | .nf 168 | .fam C 169 | $ psd p 170 | 171 | Warning! 172 | /home/facade/.mozilla/firefox/f8cv8bfu.default appears to be a symlink but these are not supported. 173 | Please make the browser profile a live directory and try again. Exiting. 174 | 175 | .fam T 176 | .fi 177 | A proper work around for firefox is to simply edit ~/.mozilla/firefox/profiles.ini defining the canonical path there. One also needs to adjust the IsRelative flag like so: 178 | .PP 179 | .nf 180 | .fam C 181 | [Profile0] 182 | Name=default 183 | IsRelative=0 184 | Path=/foo/bar/f8cv8bfu.default 185 | 186 | .fam T 187 | .fi 188 | Other solutions may exist for other browsers but documenting them all here is out of scope. 189 | .SH SUPPORTED DISTROS 190 | Since psd is just a bash script with a systemd service, it should run on any flavor of Linux running systemd. Several distros provide an official package or user-maintained option to install psd. One can also build psd from source. See the official website for available packages, dependencies, and installation instructions 191 | .SH FAQ 192 | Q1: What is overlayfs mode? 193 | .PP 194 | A1: Overlayfs is a simple union filesystem mainlined in the Linux kernel version 3.18.0. When used with psd, a reduced memory footprint and faster sync operations can be realized. The magic is in how the overlay mount only writes out data that has changed rather than the entire profile. The same recovery features psd uses in its default mode are also active when running in overlayfs mode. 195 | .PP 196 | See the example in the PREVIEW MODE section above which shows a system using overlayfs to illustrate the typical memory savings. Note the "overlayfs size" report compared to the total "profile size" report for each profile. Be aware that these numbers will change depending on just how much new data is written to the profile, but in common use cases, the overlayfs size will always be less than the profile size. 197 | .PP 198 | Q2: How do I enable overlayfs mode? 199 | .PP 200 | A2: First, be sure psd is not active or else any changes to the config file will be ignored until it is restarted. Overlayfs mode is enabled with the USE_OVERLAYFS= variable which should be set to "yes" in the config file. Psd will automatically detect the overlayfs version available to the kernel if it is configured to use one of them. It is recommended to run psd in preview mode to verify that the system can in fact use overlayfs. 201 | .PP 202 | Users wanting to use overlayfs mode MUST have sudo rights without password prompt to /usr/bin/psd-overlay-helper or global sudo rights without password prompt. If the user does not have global rights, add the following line to /etc/sudoers after any other lines defining sudo access. It is recommended to use /usr/bin/visudo as root to set this up: 203 | .PP 204 | .nf 205 | .fam C 206 | foo ALL=(ALL) NOPASSWD: /usr/bin/psd-overlay-helper 207 | 208 | .fam T 209 | .fi 210 | Q3: Why do I have another browser profile directory "foo-back-ovfs" when I enable overlayfs? 211 | .PP 212 | A3: The way overlayfs works is to mount a read-only base copy (so-called lower dir) of the profile, and manage the new data on top of that. In order to avoid resyncing to the read-only filesystem, a copy is used instead. So using overlayfs is a trade-off: faster initial sync times and less memory usage vs. disk space in the home dir. 213 | .PP 214 | Q4: I need more memory to accommodate my profile/profiles in /run/user/xxxx. How can I allocate more? 215 | .PP 216 | A4: The standard way of controlling the size of /run/user/ is the RuntimeDirectorySize directive in logind.conf (see the man page for logind.conf for more). By default, 10% of physical memory is used but one can increase it safely. Remember that tmpfs only consumes what is actually used; the number specified here is just a maximum allowed. 217 | .PP 218 | Q5: My system crashed for some reason and psd didn't sync back. What do I do? 219 | .PP 220 | A5: The "last good" backup of the browser profile/profiles should be the filesystem. Upon restarting psd (on a reboot for example), a check is performed to see if the symlink to the tmpfs copy of the profile is invalid. If it is invalid, psd will snapshot the "last good" backup before it rotates it back into place. This is more for a sanity check that psd did no harm and that any data loss was a function of something else. 221 | .PP 222 | Q6: Where can I find this snapshot? 223 | .PP 224 | A6: It depends on the browser. The snapshot will be located in the same directory as the browser profile and it will contain a date-time-stamp that corresponds to the time at which the recovery took place. For example, a chromium snapshot will be ~/.config/chromium-backup-crashrecovery-20130912_153310 -- of course, the date_time suffix will be different. 225 | .PP 226 | Q7: How can I restore the snapshot? 227 | .PP 228 | A7: Follow these steps: 229 | .RS 230 | .IP 1. 4 231 | Stop psd. 232 | .IP 2. 4 233 | Move the "bad" copy of the profile to a backup (don't blindly delete anything). 234 | .IP 3. 4 235 | Copy the snapshot directory to the name that browser expects. 236 | .PP 237 | Example using chromium: 238 | .IP 1. 4 239 | systemctl \fB--user\fP stop psd.service 240 | .IP 2. 4 241 | mv ~/.config/chromium ~/.config/chromium-bad 242 | .IP 3. 4 243 | cp \fB-a\fP ~/.config/chromium-backup-crashrecovery-20130912_153310 ~/.config/chromium 244 | .RE 245 | .PP 246 | At this point, launch chromium which will use the backup snapshot just copied into place. If all is well, it is safe to delete ~/.config/chromium-bad and the snapshot. Remember, to start psd, no browsers must be open (or psd will refuse to start). 247 | .PP 248 | Q8: Can psd delete the snapshots automatically? 249 | .PP 250 | A8: Yes, run psd with the "clean" switch to delete snapshots. 251 | .SH CONTRIBUTE 252 | Users wishing to contribute to this project, should fork it and send a pull request. Source is freely available on github. 253 | .SH BUGS 254 | Discovered a bug? Please open an issue. 255 | .RS 256 | .IP \(bu 3 257 | Several cases of data loss have been reported when using eCryptFS and psd, therefore until this issue is flushed out, users of eCryptFS are encouraged not to use psd unless willing to help troubleshoot suspected browser corruption. See: https://github.com/graysky2/profile-sync-daemon/issues/158 258 | .SH ONLINE 259 | .IP \(bu 3 260 | Project page: https://github.com/graysky2/profile-sync-daemon 261 | .IP \(bu 3 262 | Wiki page: https://wiki.archlinux.org/index.php/Profile-sync-daemon 263 | .SH AUTHOR 264 | graysky (graysky AT archlinux DOT us) 265 | -------------------------------------------------------------------------------- /init/psd-resync.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Timed resync 3 | After=psd.service 4 | Wants=psd-resync.timer 5 | BindsTo=psd.service 6 | 7 | [Service] 8 | Slice=background.slice 9 | Type=oneshot 10 | ExecStart=/usr/bin/profile-sync-daemon resync 11 | Environment=LAUNCHED_BY_SYSTEMD=1 12 | 13 | [Install] 14 | WantedBy=default.target 15 | -------------------------------------------------------------------------------- /init/psd-resync.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Timer for profile-sync-daemon - 1Hour 3 | BindsTo=psd.service 4 | 5 | [Timer] 6 | OnUnitActiveSec=1h 7 | -------------------------------------------------------------------------------- /init/psd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Profile-sync-daemon 3 | Documentation=man:psd(1) man:profile-sync-daemon(1) 4 | Documentation=https://wiki.archlinux.org/index.php/Profile-sync-daemon 5 | Wants=psd-resync.service 6 | RequiresMountsFor=/home/ 7 | After=winbindd.service 8 | 9 | [Service] 10 | Slice=background.slice 11 | Type=oneshot 12 | RemainAfterExit=yes 13 | ExecStart=/usr/bin/profile-sync-daemon startup 14 | ExecStop=/usr/bin/profile-sync-daemon unsync 15 | Environment=LAUNCHED_BY_SYSTEMD=1 16 | 17 | [Install] 18 | WantedBy=default.target 19 | --------------------------------------------------------------------------------