Home / Alt manpages / dotlock.mailutils(1)

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

Lock Mail Spool Files Safely with dotlock.mailutils

You will create an mbox-style lock beside a mail spool file, detect an existing lock, and remove your own lock when the protected operation finishes. The examples use GNU Mailutils 3.17 from package mailutils 1:3.17-1.1build3. Allow about ten minutes for a local test. You need a shell, a mail spool file that the current user can access, and enough 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 unlock a live spool file merely because the lock looks old. Another process may still be reading or updating the mailbox.

1. Check the installed command

Use the canonical command name and record the version before relying on examples. This 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 installed. The command accepts one file operand. It locks that file, rather than opening or editing the mail inside it.

2. Make a disposable mailbox for the first test

Do not start with a production spool. Create a temporary mbox-like file and a directory that 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 in your shell. The placeholder output contains an ellipsis because the owner, group and file size are machine-specific. This setup is unprivileged. A real file such as /var/mail/ACCOUNT may need sudo, or it may be deliberately inaccessible to you. Do not change its ownership or permissions just to make a test work.

3. Acquire the lock

Run the command with configuration loading disabled while learning its direct command-line behaviour. This avoids an unexpected user or site configuration file adding options:

$ 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. The lock file is 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 status, not a lock-file format.

Checkpoint

Status 0 means the lock operation succeeded. Your protected program must now run between this command and the matching unlock operation. If the program has a built-in Mailutils locking facility, use that facility instead of layering an unrelated lock around it.

4. Prove that a second locker is rejected

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

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

Exit status 3 specifically means that locking failed because the file is already locked. With --debug, the installed command reports 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 is shortened above only to keep the example readable. In a script, branch on the status rather than matching the human-readable diagnostic. Status 1 means another kind of error, such as a missing file, an unusable directory or insufficient permission. Always preserve the distinction between contention and an operational failure.

5. Wait briefly when contention is expected

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

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

This command can take several seconds while it makes its attempts. It still returns 0 only after acquiring the lock; otherwise handle its non-zero status. Do not use retries to hide a permanent permission problem or an abandoned lock. In a service, log the file name, the final status and the amount of time spent waiting.

6. Unlock only after the protected work

When your operation has finished cleanly, remove the lock using 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

Use shell cleanup so an interrupted test does not leave its disposable lock behind:

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

The cleanup is best-effort. It should not make a failed mail operation look successful. For a production program, arrange its normal unlock path according to that program's error handling and ensure the lock is not released while another process can still touch the spool.

7. Investigate a stale lock carefully

If a process crashed, its companion lock may remain. First identify the exact mailbox and check which processes are using it with your normal operating-system tools. Add --debug to obtain the Mailutils failure reason, and consider --pid-check when the lock owner PID check is appropriate for your environment:

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

A failed attempt is useful evidence, not permission to break the lock. Only after confirming that no legitimate mail process owns the mailbox should an administrator consider --force=MINUTES. That option forcibly breaks an existing lock older than the supplied age. It changes coordination state and can allow concurrent writers, so use the smallest justified scope and record why it was safe. Do not run it in an unattended recovery job based only on file age.

If the mailbox or its directory is root-owned, stop and hand the check to the system's mail administrator. Elevation can make the command run, but it cannot tell you whether removing the lock will corrupt a concurrent update.

Done means

  • The installed version was checked and the canonical dotlock.mailutils command was used.
  • A disposable mailbox acquired a companion .lock file and returned status 0.
  • A second acquisition returned status 3, so contention is not confused with a generic error.
  • The matching --unlock operation removed the test lock after the protected work.
  • Retries are bounded, and force-unlocking is reserved for a verified stale lock with administrative approval.