/lib/bilibop/lockfs_mount_helper is in bilibop-lockfs 0.5.0.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | #!/bin/sh
set -e
# /lib/bilibop/lockfs_mount_helper {{{
# Mount helper script for 'lockfs' filesystem type entries in /etc/fstab.
# This script cannot be run manually. The expected way to run it is the
# following:
# 1. Enable bilibop-lockfs:
# * set BILIBOP_LOCKFS to "true" in /etc/bilibop/bilibop.conf and reboot, or
# * reboot and append 'lockfs' parameter in the boot commandline
# 2. Once '/' is an union filesystem (aufs or overlay mountpoint), the
# temporary /etc/fstab is modified to replace filesystem types (third field)
# of some entries by 'lockfs' (options are modified too to remember the
# original fstype).
# 3. /sbin/mount.lockfs is created if it doesn't already exist. This can be a
# symlink to /lib/bilibop/lockfs_mount_helper if this helper is executable,
# or a copy of the helper (followed by chmod +x) if the helper is not
# executable. If the helper is missing, /sbin/mount.lockfs will be a
# poor fallback to call mount normally.
# 4. /etc/fstab is parsed by 'mount -a', and then mount calls mount.lockfs
# with the proper arguments when a 'lockfs' fstype is encountered.
# }}}
PATH="/sbin:/bin"
usage() {
cat <<EOF
${0##*/}: mount helper script for bilibop-lockfs.
This script can not be run manually, but only by a mount process,
and only if bilibop-lockfs is enabled.
EOF
}
# mount_fallback() =========================================================={{{
# What we want is: mount a device on its original mountpoint and rewrite the
# fstab entry to keep it consistent. This function should be called in case of
# error or if the device is whitelisted. This function parses the arguments of
# the script itself (i.e. mount_fallback "$@").
mount_fallback() {
${DEBUG} && echo "> mount_fallback $@" >&2
local opt options= fstype=
for opt in $(IFS=','; echo ${4}); do
case "${opt}" in
fstype=*)
eval "${opt}"
;;
*)
options="${options:+${options},}${opt}"
;;
esac
done
sed -i "s;^\s*\([^#][^ ]\+\s\+${2}\s\+\)lockfs\s.*;\1${fstype:-auto} ${options:-defaults} 0 0;" /etc/fstab
mount ${flags} ${1} ${2} ${fstype:+-t ${fstype}} ${options:+-o ${options}}
}
# ===========================================================================}}}
# Works only if the parent process is /bin/mount:
if [ "$(readlink -f /proc/${PPID}/exe)" != "/bin/mount" ]; then
usage >&2
exit 3
fi
. /lib/bilibop/common.sh
get_bilibop_variables
get_udev_root
# Works only if the root filesystem is already managed by bilibop-lockfs:
if is_aufs_mountpoint -q / && [ -f "${BILIBOP_RUNDIR}/lock" ]; then
LOCKFS="true"
METHOD="aufs"
robr="$(aufs_readonly_branch /)"
rwbr="$(aufs_writable_branch /)"
elif is_overlay_mountpoint -q / && [ -f "${BILIBOP_RUNDIR}/lock" ]; then
LOCKFS="true"
METHOD="overlay"
robr="$(overlay_lowerdir /)"
rwbr="$(overlay_upperdir /)"
else
echo "${0##*/}: bilibop-lockfs is disabled." >&2
exit 1
fi
# Some configurations can have been overridden from the boot commandline:
for param in $(cat /proc/cmdline); do
case "${param}" in
lockfs=*)
for policy in $(IFS=','; echo ${param#lockfs=}); do
case "${policy}" in
default)
BILIBOP_LOCKFS_POLICY=""
BILIBOP_LOCKFS_WHITELIST=""
BILIBOP_LOCKFS_SIZE=""
;;
hard|soft)
BILIBOP_LOCKFS_POLICY="${policy}"
;;
all)
BILIBOP_LOCKFS_WHITELIST=""
;;
-/*)
BILIBOP_LOCKFS_WHITELIST="${BILIBOP_LOCKFS_WHITELIST:+${BILIBOP_LOCKFS_WHITELIST} }${policy#-}"
;;
esac
done
;;
esac
done
# But if there is a physical lock, it takes precedence:
if [ -f "${BILIBOP_RUNDIR}/plocked" ]; then
. ${BILIBOP_RUNDIR}/plocked
fi
# the mount(8) command, after parsing commandline arguments and/or /etc/fstab,
# always provides arguments to the helper scripts in this order:
# FILESYSTEM MOUNTPOINT [FLAGS] -o MOUNTOPTIONS
# where FLAGS are generic, not filesystem specific: -n, -s, -v for example; -r
# (or --read-only) and -w (or --rw or --read-write) are translated to -o ro and
# -o rw respectively by the mount command itself.
while [ "${1}" ]; do
case "${1}" in
-o)
MNTARGS="${MNTARGS:+${MNTARGS} }${1} ${2}"
shift 2
;;
-*)
# Do not skip other options (-n, -s, -v), but take them
# apart: we will reuse them for each mount invocation.
flags="${flags:+${flags} }${1}"
shift
;;
*)
MNTARGS="${MNTARGS:+${MNTARGS} }${1}"
shift
;;
esac
done
# Reinitialize script arguments
eval set -- "${MNTARGS}"
if [ -b "${1}" ]; then
device="${1}"
# Check if this device is whitelisted:
if [ -n "${BILIBOP_LOCKFS_WHITELIST}" ]; then
# Query ID_FS_* udev environment variables of the device:
eval $(query_udev_envvar $(readlink -f ${device}))
if [ -z "${ID_FS_USAGE}" ]; then
eval $(blkid -o udev -p ${device})
fi
[ "${ID_FS_USAGE}" = "filesystem" -o "${ID_FS_USAGE}" = "crypto" ] &&
for skip in ${BILIBOP_LOCKFS_WHITELIST}; do
case "${skip}" in
UUID=${ID_FS_UUID}|LABEL=${ID_FS_LABEL}|TYPE=${ID_FS_TYPE})
LOCKFS="false"
break
;;
esac
done
fi
elif [ -f "${1}" ]; then
lofile="${1}"
LOFILE="${robr}${lofile}"
else
# There is no block device to mount (here 'block device' includes
# files associated to a loop device). Bind mounts and remote fs
# should have been discarded by the bilibop-lockfs script in the
# initramfs...
LOCKFS="false"
fi
# If bilibop-lockfs is not enabled (the device is whitelisted, or we don't
# know how to manage it), rewrite the fstab entry and do a normal mount:
if [ "${LOCKFS}" != "true" ]; then
mount_fallback "${@}"
exit $?
fi
mntpnt="${2}"
options="${4}"
# Parse mount options. Two cases:
# 1. the block device will be mounted with the same options than in the
# original fstab entry, plus 'ro'.
# 2. the tmpfs will be mounted with only some options of the previous:
# ro, nodev, noexec, nosuid, if they exist.
for opt in $(IFS=','; echo ${options}); do
# 1. Options for the readonly branch:
case "${opt}" in
fstype=*)
eval "${opt}"
;;
rw)
;;
*)
robr_opts="${robr_opts:+${robr_opts},}${opt}"
;;
esac
# 2. Options for the writable branch:
case "${opt}" in
ro|nodev|noexec|nosuid)
rwbr_opts="${rwbr_opts:+${rwbr_opts},}${opt}"
;;
*)
;;
esac
done
# For aufs:
# Several schemes are available (there was only one until bilibop 0.4.23).
# 1. nested
# Each readonly branch is mounted under the subtree of the main readonly
# branch (/aufs/ro) and each writable branch is mounted under the subtree
# of the main writable branch (/aufs/rw). For examples:
# <readonly branch> + <writable branch> -> <aufs mount>
# /aufs/ro + /aufs/rw -> /
# /aufs/ro/boot + /aufs/rw/boot -> /boot
# /aufs/ro/usr/local + /aufs/rw/usr/local -> /usr/local
# 2. isolated
# Each readonly branch is mounted beside its writable branch in a dedicated
# subdirectory referring to the union fs mount point. For examples:
# <readonly branch> + <writable branch> -> <aufs mount>
# /aufs/ro + /aufs/rw -> /
# /aufs/boot/ro + /aufs/boot/rw -> /boot
# /aufs/usr/local/ro + /aufs/usr/local/rw -> /usr/local
# 3. hybrid
#
# For overlay:
# A dedicated temporary filesystem (tmpfs) is set for the first overlay mount
# point, and readonly and writable branches (and also workdir) are
# subdirectories of the tmpfs mountpoint. Next mounts (done by this script)
# may use the same *isolated* scheme or a hybrid one. Nested scheme is not
# possible. For examples (where /overlay and /overlay/boot are the tmpfs
# mountpoints):
# 1. isolated
# <lowerdir> + <upperdir> + <workdir> -> <overlay>
# /overlay/ro + /overlay/rw + /overlay/.rw -> /
# /overlay/boot/ro + /overlay/boot/rw + /overlay/boot/.rw -> /boot
# 2. hybrid
# <lowerdir> + <upperdir> + <workdir> -> <overlay>
# /overlay/ro + /overlay/rw + /overlay/.rw -> /
# /overlay/ro/boot + /overlay/boot/rw + /overlay/boot/.rw -> /boot
#
# In any non-isolated scheme, we will create symlinks to make that
# ${UNION}${MNTPNT}/r{o,w} always exist.
#
# /aufs/usr/local/ro -> ../../ro/usr/local
# /aufs/usr/local/rw -> ../../rw/usr/local
# or
# /overlay/boot/ro -> ../ro/boot
# /overlay/rw/boot -> ../boot/rw
if [ "${METHOD}" = "aufs" ]; then
case "${BILIBOP_LOCKFS_PATH_SCHEME}" in
isolated)
# Use clearly separated mountpoints (this breaks symlinks over fs
# boundaries).
robr="${robr%/*}${mntpnt}/ro" # /aufs/usr/local/ro |ro not symlinked
rwbr="${rwbr%/*}${mntpnt}/rw" # /aufs/usr/local/rw |rw not symlinked
;;
hybrid)
# ro branches are nested, rw are isolated.
roln="${robr%/*}${mntpnt}/ro" # /aufs/usr/local/ro |ro symlink
rwln="${rwbr}${mntpnt}" # /aufs/rw/usr/local |rw symlink
robr="${robr}${mntpnt}" # /aufs/ro/usr/local |ro symlinked
rwbr="${rwbr%/*}${mntpnt}/rw" # /aufs/usr/local/rw |rw symlinked
;;
*)
# This scheme is only available with aufs; this is the only one
# available in bilibop =<0.4.23. Symlinks are now created for
# compatibility with other schemes
roln="${robr%/*}${mntpnt}/ro" # /aufs/usr/local/ro |ro symlink
rwln="${rwbr%/*}${mntpnt}/rw" # /aufs/usr/local/rw |rw symlink
robr="${robr}${mntpnt}" # /aufs/ro/usr/local |ro symlinked
rwbr="${rwbr}${mntpnt}" # /aufs/rw/usr/local |rw symlinked
;;
esac
temp="${rwbr}"
elif [ "${METHOD}" = "overlay" ]; then
# Upperdirs (writable branches) can't be nested, as they are a subdirectory
# of a tmpfs mountpoint, not the mountpoint itself.
temp="$(find_mountpoint ${rwbr})" # /overlay
temp="${temp}${mntpnt}" # /overlay/usr/local
work="${temp}/.rw" # /overlay/usr/local/.rw
rwbr="${temp}/rw" # /overlay/usr/local/rw |rw not nested
case "${BILIBOP_LOCKFS_PATH_SCHEME}" in
hybrid)
# ro branches are nested, rw are isolated.
robr="${robr}${mntpnt}" # /overlay/ro/usr/local |ro symlinked
rwln="${rwbr}${mntpnt}" # /overlay/rw/usr/local |rw symlink
roln="${temp}/ro" # /overlay/usr/local/ro |ro symlink
;;
*)
# isolated
robr="${temp}/ro" # /overlay/usr/local/ro |ro not symlinked
;;
esac
fi
# If the policy is not explicitly set to 'soft', set the block device as
# readonly, and use 'rr' aufs option to improve performances:
if [ "${BILIBOP_LOCKFS_POLICY}" = "soft" ]; then
RO="ro"
else
RO="rr"
[ -b "${device}" ] && blockdev --setro ${device}
fi
# The amount of RAM to allow to this mountpoint:
SIZE=
for size in ${BILIBOP_LOCKFS_SIZE}; do
case "${size}" in
${mntpnt}=[1-9]*)
SIZE="$(printf "${size#${mntpnt}=}" | grep '^[1-9][0-9]*[KkMmGg%]\?$')"
break
;;
esac
done
# Prepare the tmpfs mountpoint (it should not exist before this step):
if [ ! -d "${temp}" ]; then
mkdir -p ${temp}
grep -q "^${mntpnt}$" ${BILIBOP_RUNDIR}/lock ||
echo "${mntpnt}" >>${BILIBOP_RUNDIR}/lock
fi
# Try to mount the writable branch, and in case of failure, undo what
# has been done before, etc.
if ! mount ${flags} -t tmpfs -o ${rwbr_opts:+${rwbr_opts},}${SIZE:+size=${SIZE},}mode=0755 tmpfs ${temp}; then
[ "${RO}" = "rr" ] && [ -b "${device}" ] && blockdev --setrw "${device}"
mount_fallback "${@}"
exit 3
fi
# Create the needed directories; some may not exist, depending on the union fs
# type and the mount scheme.
[ -d "${robr}" ] || mkdir -p ${robr}
[ -d "${rwbr}" ] || mkdir -p ${rwbr}
if [ "${METHOD}" = "overlay" ]; then
mkdir -p ${work}
fi
# Try to mount the readonly branch. In case of failure, undo what has been
# done before, do a normal mount, rewrite the fstab entry to be consistent
# with that, and exit:
if ! mount ${flags} ${fstype:+-t ${fstype}} -o ${robr_opts:+${robr_opts},}ro ${device:-${LOFILE}} ${robr}; then
umount ${temp}
[ "${RO}" = "rr" ] && [ -b "${device}" ] && blockdev --setrw "${device}"
mount_fallback "${@}"
exit 3
fi
# Fix permissions and ownership of the writable branch (and catch the values;
# they will be reused later):
mod="$(LC_ALL=C chmod -v --reference="${robr}" "${rwbr}" | sed 's;.* \([0-7]\{4\}\) (.\+)$;\1;')"
own="$(LC_ALL=C chown -v --reference="${robr}" "${rwbr}" | sed 's;.* \([^:]\+:[^:]\+\)$;\1;')"
owner="${own%:*}"
if [ "${owner}" != "root" ]; then
uid="$(grep "^${owner}:" /etc/passwd | sed 's;^\([^:]*:\)\{2\}\([^:]\+\):.*;\2;')"
fi
group="${own#*:}"
if [ "${group}" != "root" ]; then
gid="$(grep "^${group}:" /etc/group | sed 's;^\([^:]*:\)\{2\}\([^:]\+\):.*;\2;')"
fi
# Now set the union filesystem mount options
if [ "${METHOD}" = "aufs" ]; then
UNIONFS_OPTS="br:${rwbr}=rw:${robr}=${RO}"
elif [ "${METHOD}" = "overlay" ]; then
UNIONFS_OPTS="lowerdir=${robr},upperdir=${rwbr},workdir=${work}"
fi
# Try to mount the union fs now. In case of failure, undo what has been done
# before, etc.
#
# If the virtual filesystem's arbitrary name exists in the current directory,
# then mount will record it (in /proc/mounts) by translating it as an absolute
# path (here, /aufs or /overlay), which may confuse users parsing df or mount
# output. So we move somewhere else before calling mount.
cd /tmp
if ! mount ${flags} -t ${METHOD} -o ${UNIONFS_OPTS} ${METHOD} ${mntpnt}; then
umount ${robr}
umount ${temp}
[ "${RO}" = "rr" ] && [ -b "${device}" ] && blockdev --setrw "${device}"
mount_fallback "${@}"
exit 3
fi
cd ${OLDPWD}
# Create symlinks, for example:
#
# (/overlay/)ro/usr/local: the target
# (/overlay/)usr/local/ro: the symlink
# ln -s ../../ro/usr/local /overlay/usr/local/ro
#
# (/overlay/)usr/local/rw: the target
# (/overlay/)rw/usr/local: the symlink
# ln -s ../../usr/local/rw /overlay/rw/usr/local
prefix="$(echo ${mntpnt} | sed -e 's,[^/],,g; s,/,../,g')"
if [ "${METHOD}" = "aufs" ]; then
case "${BILIBOP_LOCKFS_PATH_SCHEME}" in
isolated)
;;
hybrid)
[ -d "${rwln%/*}" ] || mkdir -p ${rwln%/*}
[ -d "${roln%/*}" ] || mkdir -p ${roln%/*}
ln -s ${prefix%/}/ro${mntpnt} ${roln}
ln -s ${prefix%/}${mntpnt}/rw ${rwln}
;;
*)
[ -d "${rwln%/*}" ] || mkdir -p ${rwln%/*}
[ -d "${roln%/*}" ] || mkdir -p ${roln%/*}
ln -s ${prefix%/}/ro${mntpnt} ${roln}
ln -s ${prefix%/}/rw${mntpnt} ${rwln}
;;
esac
elif [ "${METHOD}" = "overlay" ]; then
case "${BILIBOP_LOCKFS_PATH_SCHEME}" in
hybrid)
[ -d "${rwln%/*}" ] || mkdir -p ${rwln%/*}
[ -d "${roln%/*}" ] || mkdir -p ${roln%/*}
ln -s ${prefix%/}/ro${mntpnt} ${roln}
ln -s ${prefix%/}${mntpnt}/rw ${rwln}
;;
*)
;;
esac
fi
# All is OK. So we can rewrite fstab entry to reflect the real mounts. This
# can be important for clean unmounts at shutdown (for the case a filesystem
# is remounted rw during a session).
robr_line="${device:-${LOFILE}} ${robr} ${fstype:-auto} ${robr_opts:+${robr_opts},}ro 0 0"
rwbr_line="tmpfs ${temp} tmpfs ${rwbr_opts:+${rwbr_opts},}${SIZE:+size=${SIZE},}${uid:+uid=${uid},}${gid:+gid=${gid},}mode=${mod} 0 0"
union_line="${METHOD} ${mntpnt} ${METHOD} ${UNIONFS_OPTS} 0 0"
sed -i "s;^\s*[^#][^ ]\+\s\+${mntpnt}\s\+lockfs\s.*;${rwbr_line}\n${robr_line}\n${union_line};" /etc/fstab
# vim: et sts=4 sw=4 ts=4
|