Different users lock each other out when running with option "only one backup at a time"
Describe the problem, feature or ask a question:
When multiple users on the same box tick "Only one snapshot at a time" (or so, I use the German version) in the settings the first user creating the /tmp/backintime.lock file is the only one who can run backups. I attach the output of backintime backup --debug for another user being unable to run backups.
The python exception is somewhat misleading: the file has permissions:
-rw-rw-rw- 1 richard richard 0 Nov 27 15:11 backintime.lock
and should be writable by others (I can open the file in a text editor just fine with any user).
I tried lsof -a -p $$ on both users, there don't seem to be open file descriptors for that file (in case your code tries an exclusive write lock, I am not very knowledgable in python). If you know a better way to find open file descriptors, please let me know (I tried ls -l /proc/$$/fd as well).
As well, there is no indication whatsoever that something went wrong in the UI. It just says something along the lines "Ready, no snapshot necessary" in the status bar. Bringing up the last log shows only the log of the last successful backup. At first, this was puzzling for me as there where clearly files being newer than the last snapshot.
On a side note: I am using anacron scheduling. If I understand anacron correctly it is backed by a cron job running every 15 min. If this is combined with running only one backup at a time for multiple users/profiles there is a risk of running never a snapshot for some of the users/profiles if the snapshot is not retried outside the anacron schedule. The following might happen each time (in that order, daily jobs):
- Anacron starts for user A (process A)
- Anacron starts for user B (process B); due to how anacron works, this will be the same time as the step before (give or take some ms)
- Process A checks global lock and locks backintime globally
- Process B checks global lock and gives up
- Process B exits. Anacron job for process B is done and anacron notes that the scheduled job for that day has been run
- Process A runs its backup and releases the global lock
- Process A exits. Anacron job for process A is done and anacron notes that the scheduled job for that day has been run
If this happens every day, snapshots for user B will never being run.
Diagnostics
{
"backintime": {
"name": "Back In Time",
"version": "1.4.3",
"latest-config-version": 6,
"local-config-file": "/home/UsernameReplaced/.config/backintime/config",
"local-config-file-found": true,
"global-config-file": "/etc/backintime/config",
"global-config-file-found": false,
"started-from": "/usr/share/backintime/common",
"running-as-root": false,
"user-callback": "/home/UsernameReplaced/.config/backintime/user-callback",
"keyring-supported": true
},
"host-setup": {
"platform": "Linux-6.14.0-36-generic-x86_64-with-glibc2.39",
"system": "Linux #36~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Oct 15 15:45:17 UTC 2",
"OS": {
"/etc/os-release": "Linux Mint 22.2",
"/etc/lsb-release": "DISTRIB_ID=LinuxMint\nDISTRIB_RELEASE=22.2\nDISTRIB_CODENAME=zara\nDISTRIB_DESCRIPTION=\"Linux Mint 22.2 Zara\"\n",
"/etc/debian_version": "trixie/sid\n"
},
"display-system": "x11",
"locale": "de_DE, UTF-8",
"PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin",
"RSYNC_OLD_ARGS": "(not set)",
"RSYNC_PROTECT_ARGS": "(not set)"
},
"python-setup": {
"python": "3.12.3 main Nov 6 2025 13:44:16 CPython GCC 13.3.0",
"python-executable": "/usr/bin/python3",
"python-executable-symlink": true,
"python-executable-resolved": "/usr/bin/python3.12",
"sys.path": [
"/usr/share/backintime/qt/plugins",
"/usr/share/backintime/common/plugins",
"/usr/share/backintime/plugins",
"/usr/share/backintime/common",
"/usr/lib/python312.zip",
"/usr/lib/python3.12",
"/usr/lib/python3.12/lib-dynload",
"/usr/local/lib/python3.12/dist-packages",
"/usr/lib/python3/dist-packages",
"/usr/lib/python3.12/dist-packages"
],
"qt": {
"Version": "PyQt 5.15.10 / Qt 5.15.13",
"Theme": "Mint-X",
"Theme Search Paths": [
"/home/UsernameReplaced/.icons",
"/home/UsernameReplaced/.local/share/icons",
"/usr/share/cinnamon/icons",
"/var/lib/flatpak/exports/share/icons",
"/usr/share/icons",
":/icons"
],
"Fallback Theme": "",
"Fallback Search Paths": []
}
},
"external-programs": {
"rsync": {
"version": "3.2.7",
"protocol": "31.0",
"capabilities": {
"file_bits": 64,
"inum_bits": 64,
"timestamp_bits": 64,
"long_int_bits": 64,
"socketpairs": true,
"symlinks": true,
"symtimes": true,
"hardlinks": true,
"hardlink_specials": true,
"hardlink_symlinks": true,
"IPv6": true,
"atimes": true,
"batchfiles": true,
"inplace": true,
"append": true,
"ACLs": true,
"xattrs": true,
"secluded_args": "optional",
"iconv": true,
"prealloc": true,
"stop_at": true,
"crtimes": false
},
"optimizations": {
"SIMD_roll": true,
"asm_roll": false,
"openssl_crypto": true,
"asm_MD5": false
},
"checksum_list": [
"xxh128",
"xxh3",
"xxh64",
"md5",
"md4",
"sha1",
"none"
],
"compress_list": [
"zstd",
"lz4",
"zlibx",
"zlib",
"none"
],
"daemon_auth_list": [
"sha512",
"sha256",
"sha1",
"md5",
"md4"
]
},
"ssh": "OpenSSH_9.6p1 Ubuntu-3ubuntu13.14, OpenSSL 3.0.13 30 Jan 2024",
"sshfs": "3.7.3",
"encfs": "(no encfs)",
"shell": "/bin/bash",
"shell-version": "GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)"
}
}
Debug output
DEBUG: [common/backintime.py:589 argParse] Arguments: {'debug': True, 'command': 'backup', 'func': <function backup at 0x7c52dee4ce00>} | unknownArgs: []
DEBUG: [common/configfile.py:591 Config.setCurrentProfile] Change current profile: 1=Hauptprofil
DEBUG: [common/tools.py:186 initiate_translation] No language code. Use systems current locale.
DEBUG: [common/backintime.py:677 getConfig] config file: /home/boss/.config/backintime/config
DEBUG: [common/backintime.py:678 getConfig] share path: /home/boss/.local/share/backintime
DEBUG: [common/backintime.py:679 getConfig] profiles: 1=Hauptprofil
DEBUG: [common/pluginmanager.py:245 PluginManager.load] Register plugin path /usr/share/backintime/plugins
DEBUG: [common/pluginmanager.py:249 PluginManager.load] Probing plugin systrayiconplugin.py
DEBUG: [common/tools.py:735 is_Qt5_working] Qt5 probing result: exit code 2
DEBUG: [common/tools.py:738 is_Qt5_working] Qt5 probing stdout:
DEBUG: [common/tools.py:739 is_Qt5_working] Qt5 probing errout:
DEBUG: [common/qt5_probing.py:89 <module>] /usr/share/backintime/common/qt5_probing.py started... Call args: ['/usr/share/backintime/common/qt5_probing.py', '--debug']
DEBUG: [common/qt5_probing.py:90 <module>] Display system: x11
DEBUG: [common/qt5_probing.py:91 <module>] XDG_RUNTIME_DIR=/run/user/1000
DEBUG: [common/qt5_probing.py:92 <module>] XAUTHORITY=/home/boss/.Xauthority
DEBUG: [common/qt5_probing.py:93 <module>] QT_QPA_PLATFORM=($QT_QPA_PLATFORM is not set)
DEBUG: [common/qt5_probing.py:95 <module>] Current euid: 1000
DEBUG: [common/qt5_probing.py:126 <module>] isSystemTrayAvailable for Qt5: True
DEBUG: [common/qt5_probing.py:131 <module>] /usr/share/backintime/common/qt5_probing.py is terminating normally (exit code: 2)
DEBUG: [plugins/systrayiconplugin.py:76 init] System tray is available to show the BiT system tray icon
DEBUG: [common/pluginmanager.py:263 PluginManager.load] Add plugin systrayiconplugin.py
DEBUG: [common/pluginmanager.py:249 PluginManager.load] Probing plugin usercallbackplugin.py
DEBUG: [common/pluginmanager.py:249 PluginManager.load] Probing plugin notifyplugin.py
DEBUG: [common/pluginmanager.py:263 PluginManager.load] Add plugin notifyplugin.py
DEBUG: [common/applicationinstance.py:169 flockExclusiv] Trying to put an advisory lock on the flock file /home/boss/.local/share/backintime/worker.lock.flock
DEBUG: [common/applicationinstance.py:201 flockUnlock] Trying to remove the advisory lock from the flock file /home/boss/.local/share/backintime/worker.lock.flock
DEBUG: [common/snapshots.py:2027 Snapshots.flockExclusive] Set flock /tmp/backintime.lock
Back In Time
Version: 1.4.3
Back In Time comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; type `backintime --license' for details.
Traceback (most recent call last):
File "/usr/share/backintime/common/backintime.py", line 1190, in <module>
startApp()
File "/usr/share/backintime/common/backintime.py", line 523, in startApp
args.func(args)
File "/usr/share/backintime/common/backintime.py", line 764, in backup
ret = takeSnapshot(cfg, force)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/share/backintime/common/backintime.py", line 97, in takeSnapshot
ret = snapshots.Snapshots(cfg).backup(force)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/share/backintime/common/snapshots.py", line 732, in backup
self.flockExclusive() # global flock to block backups from other profiles or users (and run them serialized)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/share/backintime/common/snapshots.py", line 2028, in flockExclusive
self.flock = open(self.GLOBAL_FLOCK, 'w')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/tmp/backintime.lock'
Error in sys.excepthook:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 228, in partial_apport_excepthook
return apport_excepthook(binary, exc_type, exc_obj, exc_tb)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 144, in apport_excepthook
os.open(pr_filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o640), "wb"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/var/crash/_usr_share_backintime_common_backintime.py.1000.crash'
Original exception was:
Traceback (most recent call last):
File "/usr/share/backintime/common/backintime.py", line 1190, in <module>
startApp()
File "/usr/share/backintime/common/backintime.py", line 523, in startApp
args.func(args)
File "/usr/share/backintime/common/backintime.py", line 764, in backup
ret = takeSnapshot(cfg, force)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/share/backintime/common/backintime.py", line 97, in takeSnapshot
ret = snapshots.Snapshots(cfg).backup(force)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/share/backintime/common/snapshots.py", line 732, in backup
self.flockExclusive() # global flock to block backups from other profiles or users (and run them serialized)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/share/backintime/common/snapshots.py", line 2028, in flockExclusive
self.flock = open(self.GLOBAL_FLOCK, 'w')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/tmp/backintime.lock'
Hello Richard,
thank you for your report. It is quit complex and touches several topics. Let me try to help.
When multiple users on the same box tick "Only one snapshot at a time" (or so, I use the German version) in the settings the first user creating the /tmp/backintime.lock file is the only one who can run backups.
Yes, that is the desired behavior. Do you see any problem with that?
On a side note: I am using anacron scheduling.
You mean "Repeatedly (anacron)"? The string is missleading. It is not anacron that runs in the back. This schedule mode create an every-15-minutes-cron-job and BIT then will check itself if the desired time interval is over or not. Anacron itself is not involved. BIT just imitates the anacron behavior.
Sorry, I am not sure what the problem is you are describing. Of course I see the permission exception. But what is the file /var/crash/_usr_share_backintime_common_backintime.py.1000.crash? I have never seen it before.
The code around (global) flock was improved with version 1.5.3. The behavior might be the same but the debug output might have been improved.
Can you clearly reproduce the behavior?
Please read this FAQ entry to understand that your OS does not support Back In Time. Mint is Ubuntu. And the "LTS" in Ubuntu is a marketing lie. If you want something stable and fresh you should use the latest (stable) Debian GNU/Linux.
Regards, Christian
Hello Christian,
first, forget my "side note" about anacron. Should have had a look into your code first. My apologies. If I understand the code for 1.4.3 correctly, code will wait for the global lock becoming free.
The issues which remain and which were the reason I opened the bug report:
- There is no indication whatsoever in the GUI why a snapshot was not created although there are changed files. The reason is revealed only if one runs BIT from the command line.
- IMHO expected behavior for when ticking the box "run only one snapshot at a time": If there are several concurrently scheduled snapshots, one will run, the others will wait until the first one becomes finished and then the next one will start until all scheduled snapshots are finished. As far as a quick glance at your code revealed, this is exactly what you are trying to accomplish (I had a quick look at your blocking code where the exception originates from). Never I would expect this setting leading to snapshots not being run altogether for a different user. The first user creating the lock file will "win" and only his snapshots will be run.
- I don't know where the file
/var/crash/_usr_share_backintime_common_backintime.py.1000.crashcomes from. I assume that the python runtime tries to create the file when something goes wrong. The directory had restrictive permissions which I lifted. See the debug output after that attached. The problem persists. - Yes, the behavior is clearly reproducible. On two different machines.
Kind Regards Richard
Thank you for the feedback. I have not invented the flock behavior in BIT. This is from one of the previous maintainers/founders. Because of that I am not sure about all details of its behavior.
If I understand you correct: If one backup job is running, the second (concurring) job is not waiting but just won't run and is not catched up later?
Hello Christian,
yes the backup terminates with the error. I am not sure whether it will be scheduled again. But even if it was, for the same user it will run again into the same issue.
Out of curiosity, despite the permissions seemingly be correct, I ran the following from the command line:
cat test >> /tmp/backintime.lock
and to my surprise, I got a "permission denied". Seemingly the same error occurring in the python code. sudo lslocks didn't reveal any lock on the file (the owner user was not logged on when I tested this). getfacl did not reveal anything suspicious, either.
I the tried to write text into the file using a text editor, which failed, too.
Kind Regards Richard
I restarted the machine. Now the user which couldn't create a snapshot was able to do so. After that I switched to a different user which was again not able to create snapshot (same python exception).
There is some non-persistent lock being held by the first user accessing the lock file. lslocks again reveals nothing. The lock seems to persist until the machine is rebooted.
Is there any maintenance for the 1.4 code line? It seems that the locking code changed greatly for the dev branch.
Just a comment to make it easier to find this bug report (@buhtz : feel free to delete the comment if you are not comfortable with it): The problem described in this bug leads to snapshots not being created although there are files changed since the last snapshot. Key words: Missing snapshot "Nothing changed" message, although there are newer files Version 1.4.3
Workaround: remove the "Run only one snapshot at the same time" flag in the settings for all profiles and users on the same machine.
Thank you for the feedback. This behavior somehow need to be fixed and improved.
From my current knowledge I would prefer that the second BIT job just waits until the first job is finished or retry it again in a quit short time period.
Several parts of the core code base are involved. New inter process communication is planned, new logging mechanic and lot of other refactoring. all this changes will make it easier to understand and fix this issue you are describing.
So it will take its time until I'll come back to this issue.
From my current knowledge I would prefer that the second BIT job just waits until the first job is finished or retry it again in a quit short time period.
I had a quick glance at the locking code in snapshots.py (1.4.3) and flock.py(dev). Basically the logic is the same between 1.4.6 and the dev branch namely opening the locking file and acquire an exclusive lock on the file using a call to fcntl.flock(...), which blocks until the lock can be acquired. If all goes well, this will lead to the intended behavior you are describing.
The main difference between dev code line and 1.4.3 is a fancier way to determine which file to use for global locking, a better code structure to ensure releasing the lock and (crucially) opening the file for read instead of opening the file for write (all for the former). I dug out this stackoverflow conversation: https://stackoverflow.com/questions/23469301/flock-permission-denied-bash where this comment https://stackoverflow.com/a/70188810 gives an explanation what happens. I assume, that the code in 1.4 is broken since this change has been introduced in the kernel. There must be code paths in the 1.4.3 code which lead to the lock not being released properly (but that's only a wild guess, I can't find any open file descriptors on my system for the lock file). Combined with the attempt to open the file for write, the code terminates with a "permission denied" error. This bug should not be present on the dev code line as the file is opened only for read, which should be fine. Nevertheless, current code should be tested for this bug.
If there is any maintenance on older code lines, the easiest fix would be to open the lock file for read instead of write, ensuring that it exists. And maybe wrapping the calls in some try-catch blocks... Note that this does not remove the root cause which is improper handling of the file lock (it seems not to be released correctly). The dev code looks much better in that regard.
As you mentioned distributions: imho the presence of the bug is not dependent on the distribution but only on the kernel used by the distribution. Newer kernels should all have the bug (provided that BIT version 1.4.3 is used).
Kind Regards Richard
Hello Richard, thank you for breaking that down. The latest dev version is somehow improved.
See common/flock.py which is used in common/snapshots.py::backup() like this:
# Global flock to block backups from other profiles or users
# (and run them serialized). The argument "disabled" is a
# workaround (#1751) that should be removed/refactored after
# this method ("backup()") is refactored.
with flock.GlobalFlock(disable=not self.config.globalFlock()):
# logger.info('Lock', self)
now = datetime.datetime.today()
I don't remember all details but this modified kernel behavior and a "better" decision about location of the lock file in the file system was involved.
Hi, I reviewed this issue and I would like to work on clarifying the workflow. Here is what I will do:
Explain the API-breaking-change workflow step-by-step in the documentation.
Add a clear example showing how developers should handle breaking changes in modules.
Improve comments in the code so the workflow is easy to understand.
Update README or CONTRIBUTING.md with a simple explanation of the expected process.
Please confirm if this direction is correct, I will start working on it.”
@arybhatt4533: Your comment sounds like AI crap. Totally useless! Be careful. I reported your comment to the abuse department. You lost some points on your trustworthiness scale, so I am not able to review or accept any of your code you might commit.
EDIT: Usually I try to keep it cool. But today I am really pissed. But I hope you might learn somehow from it. Throwing that AI crap on projects won't help your career and it wont help this project. I count on your empathy and willing to learn. So read the following text and next time think twice before you contribute to a project:
Hello arybhatt4533,
this is a standard response we use in such situations.
We as the maintenance team are working voluntarily in our free time. We don't seek applause or fame, but ask contributors and users to respect our limited resources.
We sometimes encounter problems with AI-generated content and contributions from people farming GitHub stars, without deeper engagement in the project. It can be challenging to distinguish these from contributions by less experienced contributors who are genuinely trying to help and learn.
This issue/pull request appears incomplete or low in quality:
- Feedback requests and questions were not answered
- Some code changes appear automatically generated or inconsistent
I will close this issue/PR for now. If this assessment is mistaken, please reopen with additional context. Despite limited resources, I am happy to guide new contributors in how to effectively contribute to open source.
Regards, Christian
Sorry brother I didn't know about it am just try to use ai for clearing all doubt easily sorry sir extremely sorry 😞 because am just started GitHub previous some days
Sorry brother I didn't know about it am just try to use ai for clearing all doubt easily sorry sir extremely sorry 😞
Hope your read my text and maybe learned something.
because am just started GitHub previous some days
Please watch carefully https://www.youtube.com/watch?v=5nY_cy8zcO4