Skip to content

Commit

Permalink
Optionally symlink files from persistent source instead of mount it.
Browse files Browse the repository at this point in the history
This is done by passing the option "linkfiles" to a live.persist
entry. That option is very useful when you only want certain files
to be persistent, not the whole directory they are in, like dot-files
in $home.
  • Loading branch information
Tails developers authored and daniel-baumann committed Apr 1, 2012
1 parent 916c945 commit 2fc36d8
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 18 deletions.
87 changes: 69 additions & 18 deletions scripts/live
Expand Up @@ -1596,15 +1596,21 @@ setup_unionfs ()
# Adding other custom mounts
if [ -n "${PERSISTENT}" ] && [ -z "${NOPERSISTENT}" ]
then
bindings="/${persistence_list}"
touch ${bindings}
bindings="/bindings.list"
links="/links.list"
custom_mounts="/custom_mounts.list"
rm -f ${bindings} ${links} ${custom_mounts} >/dev/null 2>&1
persistent_backing="${rootmnt}/live/persistent"

# First we scan all media and gather all information about custom mounts
for device in ${overlay_devices}
do
if [ ! -b "${device}" ]
then
continue
fi
backing="/$(basename ${device})-backing"
device_name="$(basename ${device})"
backing="${persistent_backing}/${device_name}"
mkdir -p "${backing}"
device_fstype="$(get_fstype ${device})"
if [ -z "${PERSISTENT_READONLY}" ]
Expand All @@ -1623,34 +1629,56 @@ setup_unionfs ()
continue
fi

# FIXME: debug stuff, remove me?
[ "${DEBUG}" = "Yes" ] && cat ${include_list} >> ${rootmnt}/${bindings}-origs
while read source dest
[ "${DEBUG}" = "Yes" ] && cp ${include_list} ${persistent_backing}/${persistence_list}.${device_name}
while read source dest options # < ${include_list}
do
if echo ${source} | grep -qe "^[[:space:]]*#"
then
# skipping commented line
continue
fi
if [ -z "${dest}" ]

if echo ${dest} | grep -qe "^[^/]"
then
options="${dest}"
dest="${source}"
elif [ -z "${dest}" ]
then
dest="${source}"
fi

if echo ${dest} | grep -qe "^/\+$\|^/\+live\(/.*\)\?$"
then
# mounting on / or /live could cause trouble
log_warning_msg "Skipping unsafe custom mount on ${dest}"
continue
fi

# FIXME: handle case: we already have /a/b in $bindings, but now we find /a -- /a should replace /a/b in $bindings.
# FIXME: handle case: we have /a in $bindings, now we find /a/b, so we skip /a/b
for opt in $(echo ${options} | tr ',' ' ');
do
case "${opt}" in
"linkfiles")
;;
*)
log_warning_msg "Skipping custom mount with unkown option: ${opt}"
continue
;;
esac
done

# FIXME: handle case: we already have /a/b in $bindings added from current $device, but now we find /a -- /a should replace /a/b in $bindings.
# FIXME: handle case: we have /a in $bindings from current $device, now we find /a/b, so we skip /a/b

# ensure that no multiple-/ occur in paths
full_source="$(echo ${backing}/${source}/ | sed -e 's|/\+|/|g')"
full_dest="$(echo ${rootmnt}/${dest}/ | sed -e 's|/\+|/|g')"
device_used="yes"
echo "${full_source} ${full_dest}" >> ${bindings}
if echo ${options} | grep -qe "\<linkfiles\>";
then
echo "${full_source} ${full_dest} ${options}" >> ${links}
else
echo "${full_source} ${full_dest} ${options}" >> ${bindings}
fi
done < ${include_list}

if [ -z "${device_used}" ]
Expand All @@ -1661,13 +1689,19 @@ setup_unionfs ()
fi
done

# we sort the list according to destination so we're sure that we won't hide a previous mount. we also ignore duplicate destinations in a more or less arbitrary way
sort -k2 -sbu ${bindings} -o ${bindings}
# We sort the list according to destination so we're sure
# that we won't hide a previous mount. We also ignore
# duplicate destinations in a more or less arbitrary way.
[ -e "${bindings}" ] && sort -k2 -sbu ${bindings} >> ${custom_mounts}

# After all mounts are considered we add symlinks so they
# won't be hidden by some mount.
[ -e "${links}" ] && sort -k2 -sbu ${links} >> ${custom_mounts}

# FIXME: debug stuff, remove me?
[ "${DEBUG}" = "Yes" ] && cp ${bindings} ${rootmnt}/${bindings}-results
[ "${DEBUG}" = "Yes" ] && cp ${custom_mounts} ${persistent_backing}

while read source dest
# Now we do the actual mounting (and symlinking)
while read source dest options # < ${custom_mounts}
do
if mountpoint -q "${dest}";
then
Expand Down Expand Up @@ -1707,7 +1741,7 @@ setup_unionfs ()
# dealing with /etc or other system dir.
if [ ! -d "${source}" ]
then
if [ -n "${PERSISTENT_READONLY}" ]
if [ -n "${PERSISTENT_READONLY}" ] || echo ${options} | grep -qe "\<linkfiles\>"
then
continue
fi
Expand All @@ -1718,14 +1752,31 @@ setup_unionfs ()

if [ -z "${PERSISTENT_READONLY}" ]
then
mount --bind "${source}" "${dest}"
if echo ${options} | grep -qe "\<linkfiles\>";
then
links_source="${source}"
links_dest="${dest}"
else
mount --bind "${source}" "${dest}"
fi
else
if echo ${options} | grep -qe "\<linkfiles\>";
then
links_dest="${dest}"
dest="$(mktemp -d ${persistent_backing}/links_source-XXXXXX)"
links_source="${dest}"
fi
unionrw="$(echo ${dest} | sed -e "s|${rootmnt}|/cow/|")"
mkdir -p ${unionrw}
unionmountopts="noatime,${noxino_opt}dirs=${unionrw}=rw:${source}=${roopt}"
mount -t "${UNIONTYPE}" -o "${unionmountopts}" "${UNIONTYPE}" "${dest}"
fi
done < ${bindings}

if echo $options | grep -qe "\<linkfiles\>";
then
link_files "${links_source}" "${links_dest}" "${rootmnt}"
fi
done < ${custom_mounts}
rm -f ${bindings}

# Look for other snapshots to copy in
Expand Down
52 changes: 52 additions & 0 deletions scripts/live-helpers
Expand Up @@ -556,3 +556,55 @@ non_removable_dev ()

echo "${ret}"
}

link_files ()
{
# create source's directory structure in dest, and recursively
# create symlinks in dest to to all files in source. if mask
# is non-empty, remove mask from all source paths when
# creating links (will be necessary if we change root, which
# live-boot normally does (into $rootmnt)).

# remove multiple /:s and ensure ending on /
local src_dir="$(echo "${1}"/ | sed -e 's|/\+|/|g')"
local dest_dir="$(echo "${2}"/ | sed -e 's|/\+|/|g')"
local src_mask="${3}"

# This check can only trigger on the inital, non-recursive call since
# we create the destination before recursive calls
if [ ! -d "${dest_dir}" ];
then
log_warning_msg "Must link_files into a directory"
return
fi

find "${src_dir}" -mindepth 1 -maxdepth 1 | while read x; do
local src="${x}"
local dest="${dest_dir}$(basename "${x}")"
if [ -d "${src}" ];
then
if [ -z "$(ls -A "${src}")" ];
then
continue
fi
if [ ! -d "${dest}" ];
then
mkdir -p "${dest}"
prev="$(dirname "${dest}")"
chown $(stat -c %u:%g "${prev}") "${dest}"
chmod $(stat -c %a "${prev}") "${dest}"
fi
link_files "${src}" "${dest}" "${src_mask}"
else
if [ -e "${dest}" ];
then
rm -rf "${dest}"
fi
if [ -n "${src}" ];
then
src="$(echo ${src} | sed "s|^${src_mask}||")"
fi
ln -s "${src}" "${dest}"
fi
done
}

0 comments on commit 2fc36d8

Please sign in to comment.