1

I would like to avoid setting up an IMAP server and instead use mailutils' movemail in combination with SSHFS to move over some mails from an external host to my local machine. Unfortunately it fails:

$ sshfs -o noforget exthost:/ /mnt/sshfs
$ movemail /mnt/sshfs/var/mail/dirdi /home/user/dirdi/ext_mail
movemail: mailbox `/mnt/sshfs/var/mail/dirdi': cannot lock: Lock file check failed

However, the lock file /var/mail/dirdi.lock is actually being created on exthost. I had a look at the source code and tracked the error down until here: http://git.savannah.gnu.org/cgit/mailutils.git/tree/libmailutils/base/locker.c?h=release-3.5#n120 It seems to me that some check inside the stat_check function fails, but I can not tell which and why.

1 Answer 1

0

As a workaround I created smovemail, a shell script which runs movemail on a local copy of the remote mailbox:

#!/bin/bash

# initialize variables
status=0
src=
dest=
remotefs=
copy=
mountpoint=
lockfile=

# function to print errors
function error {
    echo "(E) ${1}" >&2
    status=1
}

# function to tear down created environment
function tear_down {

    # remove local copy of remote mailbox
    if [[ "${copy}" ]]; then
        rm -- "${copy}" ||
            error "Unable to remove local copy of remote mailbox '${copy}.'"
    fi

    # remove lockfile
    if [[ "${lockfile}" ]]; then
        rm -- "${lockfile}" ||
            error "Unable to remove lockfile '${lockfile}. Remote mailbox may still be locked.'"
    fi

    # unmount SSHFS
    mount | cut -d " " -f 3 | grep "${mountpoint}" >/dev/null &&
        fusermount -u "${mountpoint}" 2>/dev/null ||
            error "Unable to unmount remote filesystem mounted at '${mountpoint}'"

    # remove mountpoint
    if [[ "${mountpoint}" ]]; then
        rmdir "${mountpoint}" 2>/dev/null ||
            error "Unable to remove mountpoint '${mountpoint}'"
    fi

    exit ${status}
}

# register tear down function to run in any case
trap tear_down EXIT

# print usage
if [[ ${#} -ne 2 ]]; then
    error "Usage: $(basename ${0}) remote_mailbox local_mailbox"
    exit
fi
# TODO implement better parameter sanitization

# create mountpoint
mountpoint=$(mktemp -d 2>/dev/null) || {
    error "Unable to create mountpoint."
    exit
}

# determine locations
src="${mountpoint}/"$(basename "${1}" 2>/dev/null)
remotefs=$(dirname "${1}" 2>/dev/null)
dest="${2}"

# mount SSHFS
sshfs "${remotefs}" "${mountpoint}" -o workaround=rename,reconnect,uid=$(id -u),gid=$(id -g) >/dev/null 2>&1 || {
    error "Unable to mount remote filesystem '${remotefs}'"
    exit
}

# lock remote mailbox
lockfile=$(mktemp -p "${mountpoint}" 2>/dev/null) || {
    error "Unable to create lockfile"
    exit
}
mv -n "${lockfile}" "${src}.lock"
if [[ -f "${lockfile}" ]]; then
    error "Unable to lock mailbox."
    exit
fi
lockfile="${src}.lock"

# create local copy
copy=$(mktemp 2>/dev/null) || {
    error "Unable to create copy of remote mailbox."
    exit
}
cp "${src}" "${copy}" 2>/dev/null || {
    error "Unable to copy remote mailbox."
    exit
}

# run movemail
movemail "${copy}" "${dest}" || {
    error "Unable to move mails."
    exit
}

# play back copy
cp "${copy}" "${src}" 2>/dev/null || {
    error "Unable to play back local copy."
    exit
}

It can be invoked by $ smovemail remoteuser@remotehost:/var/mail/remoteuser /var/mail/localuser

If you want to use this script, feel free to do so, but please note: This script leverages the mv -n command to lock the remote mailbox and therefore is based on the assumption that this command is atomic on SSHFS filesystems. Based on my research this assumption does not always hold! However, I ran some tests and was not able to crash it, so for me it is good enough.

Comments and suggestions for improvements are very welcome.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .