Home / Alt manpages / dotlock.mailutils(1)

  • dotlock.mailutils(1)
  • User command
  • linux

Lock Mail Spool Files Safely with dotlock.mailutils

A shared mbox spool with no lock file lets two mail programs write over each other, and one bad interleave can wipe the mailbox. dotlock.mailutils creates and clears that lock file so only one process touches the spool at a time. The examples below use GNU Mailutils 3.17 from package mailutils 1:3.17-1.1build3 and take about ten minutes on a throwaway test file. You need a shell, a mail spool file the current user can access, and permission to create its lock file.

Warning

Locking is coordination, not a backup and not a replacement for the mail delivery program's documented workflow. Do not remove a live lock merely because it looks old: another process may still be reading or updating the mailbox.

1. Check the installed command

Confirm the exact binary and version before trusting any example below, this one included. The check is read-only and normally needs no elevated privileges:

$ command -v dotlock.mailutils
/usr/bin/dotlock.mailutils
$ dotlock.mailutils --version
dotlock.mailutils (GNU Mailutils) 3.17
$ dpkg-query -W -f='${Package} ${Version}\n' mailutils
mailutils 1:3.17-1.1build3

The installed dotlock name is an alias for the same purpose, but spelling out dotlock.mailutils makes the provider clear when several mail tools are on the box. The command takes one file operand: it locks that file, it does not open or edit the mail inside it.

2. Make a disposable mailbox for the first test

Skip the production spool for now. Build a throwaway mbox-style file and a directory only you use:

$ test_dir=$(mktemp -d /tmp/dotlock-test.XXXXXX)
$ printf '%s\n' 'From [email protected] Thu Jan  1 00:00:00 1970' 'Subject: lock test' '' 'body' > "$test_dir/mailbox"
$ ls -l "$test_dir/mailbox"
-rw-r--r-- 1 ... mailbox

Keep test_dir set in your shell for the rest of this guide. The ... in the sample output stands in for owner, group and size, all of which are machine-specific. This setup needs no special privileges. A real file such as /var/mail/ACCOUNT may need sudo, or it may be deliberately off-limits to you, in which case do not change its ownership or permissions just to make a test run.

3. Take the lock

Run with configuration loading disabled while you learn the command's direct behaviour, so a user or site config file cannot quietly add options you didn't ask for:

$ dotlock.mailutils --no-config "$test_dir/mailbox"
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ find "$test_dir" -maxdepth 1 -type f -printf '%f %s bytes\n' | sort
mailbox 71 bytes
mailbox.lock 0 bytes

On this installed release, a successful lock creates the companion file mailbox.lock, empty in this test. Do not write mail data into it or treat its contents as a portable owner record: the documented interface is the command and its exit status, not the lock file's format.

Checkpoint

Status 0 means the lock succeeded. Run your protected program now, between this command and the matching release. If that program has its own Mailutils locking built in, use that instead of wrapping an unrelated lock around it.

4. Prove a second locker gets rejected

Leave the first lock in place and try to take it again:

$ dotlock.mailutils --no-config "$test_dir/mailbox"
$ printf 'exit status: %s\n' "$?"
exit status: 3

Exit status 3 specifically means locking failed because the file is already locked. Add --debug and the command names the reason on standard error:

$ dotlock.mailutils --no-config --debug "$test_dir/mailbox"
dotlock.mailutils: locking the file .../mailbox failed: Conflict with previous locker
$ printf 'exit status: %s\n' "$?"
exit status: 3

The path above is shortened only to keep the example readable. In a script, branch on the exit status rather than matching the human-readable text. Status 1 means a different kind of failure: a missing file, an unusable directory, insufficient permission. Keep contention and an operational failure distinct.

5. Wait it out when contention is expected

If another process normally holds the spool for a short time, ask dotlock to retry rather than fail immediately. Retry count and delay are separate options:

$ dotlock.mailutils --no-config --retry=5 --delay=2 /path/to/mailbox

This can take several seconds while it makes its attempts, and it still only returns 0 once it actually has the lock; treat anything else as a failure to handle. Do not use retries to paper over a permanent permission problem or an abandoned lock. In a service, log the file name, the final status and how long you waited.

6. Release the lock, not before the work is done

Once your operation has finished cleanly, clear the lock with the same file operand:

$ dotlock.mailutils --no-config --unlock "$test_dir/mailbox"
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ test ! -e "$test_dir/mailbox.lock" && echo 'lock removed'
lock removed

Wire this into shell cleanup so an interrupted test does not leave its throwaway lock behind:

cleanup() {
    dotlock.mailutils --no-config --unlock "$test_dir/mailbox" >/dev/null 2>&1 || :
}
trap cleanup EXIT INT TERM

That cleanup is best-effort: it should never make a failed mail operation look like it succeeded. For a production program, follow that program's own error handling for its normal release path, and make sure the lock stays in place while another process can still reach the spool.

7. Investigate a stale lock carefully

If a process crashed, its companion lock file can outlive it. Identify the exact mailbox first, check which processes are using it with your normal OS tools, add --debug for the Mailutils failure reason, and consider --pid-check where checking the lock owner's PID makes sense for your setup:

$ dotlock.mailutils --no-config --debug --pid-check /path/to/mailbox
$ printf 'exit status: %s\n' "$?"
exit status: 3

A failed attempt is evidence, not permission to break the lock yourself. Only after confirming no legitimate mail process owns the mailbox should an administrator reach for --force=MINUTES, which forcibly breaks a lock older than the given age. That changes coordination state and can let two writers in at once, so use the smallest justified age and record why it was safe. Never run it in an unattended recovery job based on file age alone.

If the mailbox or its directory is root-owned, stop and hand the check to the mail administrator. Elevating your own privileges can make the command run, but it cannot tell you whether breaking the lock will corrupt a concurrent update.

Done means

  • Checked the installed version and used the canonical dotlock.mailutils command name.
  • Locked a disposable mailbox and saw the companion .lock file and status 0.
  • Confirmed contention is distinct: a second attempt returned status 3, not a generic error.
  • Released the lock with the matching operation once the protected work finished.
  • Reserved force-breaking a lock for a verified stale case with administrative sign-off.