#!/bin/sh

# Copyright (c) 2015 SpinetiX.
#
# Utility functions and global variables to use by media-mount and hooks
#

#
# Constants
#

# The base of the fstab tmp file name, must reside in same dir as fstab
TMPFSTABBASE=/etc/fstab.media-

# The system configuration file for media-mount
SYSCONFIGFILE=/etc/default/media-mount

# The directory of managed mountpoints
MEDIADIR=/media

# The state directory, uses /run since that is initialized read-write
# before udev starts and hence it is always available when calling
# media-mount scripts
STATEDIR=/run/media-mount

# The media-mount error state file, if present we cannot process actions
ERRORFILE="$STATEDIR"/error

# The file with all the pending actions
PENDINGFILE="$STATEDIR"/pending-actions

# The file to indicate that everything is read and media-mount
# can do its work directly instead of entering pending actions
READYFILE="$STATEDIR"/ready

# The file to lock the state dir
STATELOCKFILE="$STATEDIR"/lock

# The maximum number of tries for locking the state dir and fstab
MAX_LOCK_TRIES=15

# The mount configuration file, if present at the root of the mounted fs
# it provides the configuration directives for the mount.
MOUNTCONFIGFILE=".spx-mount"

#
# Variable initializations
#

# Variable where mktmpfstab store the temp file name
TMPFSTAB=

#
# Helper functions
#

load_sysconfig() {
    [ -f "$SYSCONFIGFILE" ] && . "$SYSCONFIGFILE"
}

# NOTE: we use mv from a temp file in the same dir to update fstab so that the
# update is atomic (since mv will do a rename); this avoids problems with
# having a half-updated fstab file if the device is unexpectedly turned off.

# Creates a copy of a fstab in a temporary file, the temporary file name
# is stored in the TMPFSTAB variable
mktmpfstab() {
    TMPFSTAB="$(mktemp "$TMPFSTABBASE"XXXXXX)" || return 1
    # The cp -p preserves owner, mode, etc, and also initializes the
    # temp file as a copy of fstab
    cp -p /etc/fstab "$TMPFSTAB" && return 0
    rm -f "$TMPFSTAB"
    TMPFSTAB=
    return 1
}

# Saves the temporary fstab in $TMPFSTAB as fstab, if it fails the
# temporary file is removed
savetmpfstab() {
    local f="$TMPFSTAB"
    TMPFSTAB=
    if [ ! -s "$f" ]; then
        rm -f "$f"
        return 1
    fi
    fsync "$f" && mv -f "$f" /etc/fstab && return 0
    rm -f "$f"
    return 1
}

# Removes the temporary fstab in $TMPFSTAB
rmtmpfstab() {
    local f="$TMPFSTAB"
    TMPFSTAB=
    [ -e "$f" ] || return 0
    rm -f "$f"
}

# Removes all tempoerary fstab files (possibly stray files)
cleantmpfstab() {
    TMPFSTAB=
    rm -f "$TMPFSTABBASE"*
}

# Checks if there is anything mounted at the given mount point
is_any_mounted_at() {
    local mptmatch="${1%/}"
    local dev mpt fstype opts dump pass junk
    while read dev mpt fstype opts dump pass junk; do
        [ "$dev" = "" -o "$dev" = "#" ] && continue # comment or empty line
        [ "${mpt%/}" = "$mptmatch" ] && return 0
    done < /proc/mounts
    return 1
}

#
# Locking.
#
# If taking the state lock it must be taken before taking the fstab lock;
# if not taking the state lock then the fstab lock can be grabbed directly.
#

# State locking and unlocking, also referenced in related boot script
# so do not change the paths!
state_lock() {
    for (( i=1; i <= $MAX_LOCK_TRIES; i++ )) ; do
        dotlockfile -p -r 0 -l "$STATELOCKFILE" && return 0
        sleep 1
    done
    echo "ERROR: failed acquiring state lock"
    return 1
}

state_unlock() {
    dotlockfile -p -u "$STATELOCKFILE"
}

#
# /etc/fstab locking uses /var/run/fstab.lock
#
# WARNING: the lock file is also used from other scripts, so DO NOT CHANGE
# the lockfile path.

fstab_lock() {
    for (( i=1; i <= $MAX_LOCK_TRIES; i++ )) ; do
        dotlockfile -p -r 0 -l /var/run/fstab.lock && return 0
        sleep 1
    done
    echo "ERROR: failed acquiring fstab lock"
    return 1
}

fstab_unlock() {
    dotlockfile -p -u /var/run/fstab.lock
}
