#!/bin/sh

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

#
# Constants
#

# The base of the fstab tmp file, 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, needs to be under /dev because
# udev may start queuing events even before the root fs
# is read-write and /dev is the only guaranteed read-write place
STATEDIR=/dev/.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
    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 /etc/fstab.lock
#
# This also serves for us to wait for the filesystem on which /etc/fstab
# resides to be mounted read-write (although by the time we try to lock
# /etc/fstab the root fs should be read-write)
#
# 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 /etc/fstab.lock && return 0
		sleep 1
	done
	echo "ERROR: failed acquiring fstab lock"
	return 1
}

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