New features for live-snapshot
Hi all,
I released a new version of live-snapshot which supports a new way to create
snapshots and a commodity feature to resync in run existing ones.
You could now create a file named /etc/live-snapshot.list in which all files
and dirs presents there will be copied in a cpio archive at reboot or when
using --refresh, so you could create fine grained snapshots for your
applications. If you include "/etc/live-snapshot.list" in /etc/live-
snapshot.list you could also save the current selection.
So for a rapid how-to, boot your debian-live cd with "persistent" specified as
boot parameter and launch "live-snapshot" with root permissions without
parameters, copy the resulting file on a writable media (like a partition or
usb key) and reboot (or add a magic line to "/etc/live.conf").
> From now on, your live systems will take track of files specified on
/etc/live-snapshot.list, you just need to have "persistent" in and the
required software on your initramfs (that often means this patch merged in
live-initramfs).
Feel free to extend it or rename all variables with some underscores, refactor
it to death or just put silly comments on fibonacci numbered lines.
Anyway it is tested and it worked with cpio targets.
diff --git a/Makefile b/Makefile
index 30af16d..361a98d 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,8 @@ install: test build
cp -r COPYING docs/* $(DESTDIR)/usr/share/doc/live-initramfs
mkdir -p $(DESTDIR)/usr/share/doc/live-initramfs/examples
- cp -r conf/live.conf $(DESTDIR)/usr/share/doc/live-initramfs/examples
+ # All examples configuration files to examples (only live.conf, live-
snapshot.list yet)
+ cp -r conf/* $(DESTDIR)/usr/share/doc/live-initramfs/examples
# Installing manpages
set -e; for MANPAGE in manpages/*.en.1; \
diff --git a/bin/live-snapshot b/bin/live-snapshot
index b5a7fa4..abc6a42 100755
--- a/bin/live-snapshot
+++ b/bin/live-snapshot
@@ -6,7 +6,7 @@
# and save the /live/cow (or a different dir) filesystem in it for reusing
# in another live-initramfs session. Look at manpage for more info.
#
-# Copyright (C) 2006 Marco Amadori <marco.amadori at gmail.com>
+# Copyright (C) 2006,2008 Marco Amadori <marco.amadori at gmail.com>
# Copyright (C) 2008 Chris Lamb <chris at chris-lamb.co.uk>
#
# This program is free software; you can redistribute it and/or modify
@@ -33,52 +33,59 @@ set -eu
export USERNAME USERFULLNAME HOSTNAME
-PROGRAM="$(basename $0)"
-VERSION=0.0.2
+EXECUTABLE="${0}"
+PROGRAM_NAME=$(basename "${EXECUTABLE}")
# Needs to be available at run and reboot time
SAFE_TMPDIR="/live"
+# Some defaults
# Permits multiple runs
MOUNTP="$(mktemp -d -p ${SAFE_TMPDIR} live-snapshot-mnt.XXXXXX)"
-SNAP_COW="/live/cow"
+DEF_SNAP_COW="/live/cow"
+SNAP_COW="${DEF_SNAP_COW}"
+LIVE_CONF="/etc/live.conf"
SNAP_DEV=""
DEST="${MOUNTP}/live-sn.cpio.gz"
SNAP_TYPE="cpio"
DESKTOP_LINK="/home/${USERNAME}/Desktop/live-snapshot"
+SNAP_LIST="/etc/live-snapshot.list"
SNAP_RESYNC_STRING=""
+TMP_FILELIST="${PROGRAM_NAME}.list"
-Error ()
+handle_error ()
{
- echo "${PROGRAM}: error:" ${@}
+ echo "${PROGRAM_NAME}: error:" ${@}
exit 1
}
panic ()
{
- Error ${@}
+ handle_error ${@}
}
-Header ()
+header ()
{
- echo "${PROGRAM} - utility to perform snapshots of Debian Live systems"
+ echo "${PROGRAM_NAME} - utility to perform snapshots of Debian Live systems"
echo
- echo "usage: ${PROGRAM} [-c|--cow DIRECTORY] [-d|--device DEVICE] [-o|--
output FILE] [-t|--type TYPE]"
- echo " ${PROGRAM} [-r|--resync-string STRING]"
- echo " ${PROGRAM} [-h|--help]"
- echo " ${PROGRAM} [-u|--usage]"
- echo " ${PROGRAM} [-v|--version]"
+ echo "usage: ${PROGRAM_NAME} [-c|--cow DIRECTORY] [-d|--device DEVICE] [-
o|--output FILE] [-t|--type TYPE]"
+ echo " ${PROGRAM_NAME} [-r|--resync-string STRING]"
+ echo " ${PROGRAM_NAME} [-f|--refresh]"
+ echo " ${PROGRAM_NAME} [-h|--help]"
+ echo " ${PROGRAM_NAME} [-u|--usage]"
+ echo " ${PROGRAM_NAME} [-v|--version]"
}
-Help ()
+help ()
{
- Header
+ header
echo
echo "Options:"
echo " -c, --cow: copy on write directory (default: ${SNAP_COW})."
echo " -d, --device: output snapshot device (default: ${SNAP_DEV:-auto})."
echo " -o, --output: output image file (default: ${DEST})."
+ echo " -f, --refresh: try to sync a running snapshot."
echo " -r, --resync-string: internally used to resync previous made
snapshots."
echo " -t, --type: snapshot filesystem type. Options: \"squashfs\",
\"ext2\", \"ext3\", \"jffs2\" or \"cpio\".gz archive (default: ${SNAP_TYPE})"
echo
@@ -87,20 +94,20 @@ Help ()
exit 0
}
-Usage ()
+usage ()
{
- Header
+ header
echo
- echo "Try \"${PROGRAM} --help\" for more information."
+ echo "Try \"${PROGRAM_NAME} --help\" for more information."
exit 0
}
-
-Version ()
+
+version ()
{
- echo "${PROGRAM}, version ${VERSION}"
+ echo "${PROGRAM_NAME}, version ${VERSION}"
echo
echo "Copyright (C) 2006 Marco Amadori <marco.amadori at gmail.com>"
echo
@@ -126,24 +133,41 @@ Version ()
exit 0
}
-Is_same_mount ()
+try_refresh ()
{
- dir1="$(Base_path ${1})"
- dir2="$(Base_path ${2})"
-
- if [ "${dir1}" = "${dir2}" ]
+ if [ -f "${LIVE_CONF}" ]
then
- return 0
+ # declare two external vars because of "set -u"
+ ROOTSNAP=""
+ HOMESNAP=""
+ # Source conf file
+ . "${LIVE_CONF}"
+ if [ -n "${ROOTSNAP}" ]; then
+ "${EXECUTABLE}" --resync-string="${ROOTSNAP}"
+ FOUND="Yes"
+ fi
+
+ if [ -n "${HOMESNAP}" ]; then
+ "${EXECUTABLE}" --resync-string="${HOMESNAP}"
+ FOUND="Yes"
+ fi
else
- return 1
+ echo "${LIVE_CONF} missing"
+ exit 1
+ fi
+ if [ -z "${FOUND}" ]
+ then
+ echo "No autoconfigured snapshots found at boot;" >/dev/null 1>&2
+ echo "(no resync string in ${LIVE_CONF}." >/dev/null 1>&2
+ exit 1
fi
}
-Parse_args ()
+parse_args ()
{
# Parse command line
ARGS="${*}"
- ARGUMENTS="$(getopt --longoptions cow:,device:,output,resync-
string:,type:,help,usage,version --name=${PROGRAM} --options c:d:o:t:r:,h,u,v
--shell sh -- ${ARGS})"
+ ARGUMENTS="$(getopt --longoptions cow:,device:,output,resync-
string:,refresh,type:,help,usage,version --name=${PROGRAM_NAME} --options
c:d:o:t:r:fhuv --shell sh -- ${ARGS})"
eval set -- "${ARGUMENTS}"
@@ -175,16 +199,21 @@ Parse_args ()
break
;;
+ -f|--refresh)
+ try_refresh
+ exit 0
+ ;;
+
-h|--help)
- Help
+ help
;;
-u|--usage)
- Usage
+ usage
;;
-v|--version)
- Version
+ version
;;
--)
@@ -193,7 +222,7 @@ Parse_args ()
;;
*)
- Error "internal error."
+ handle_error "internal error."
;;
esac
@@ -201,14 +230,14 @@ Parse_args ()
}
-Defaults ()
+defaults ()
{
# Parse resync string
if [ -n "${SNAP_RESYNC_STRING}" ]
then
SNAP_COW=$(echo "${SNAP_RESYNC_STRING}" | cut -f1 -d ':')
SNAP_DEV=$(echo "${SNAP_RESYNC_STRING}" | cut -f2 -d ':')
- DEST=$(echo "${SNAP_RESYNC_STRING}" | cut -f3 -d ':')
+ DEST="${MOUNTP}/$(echo ${SNAP_RESYNC_STRING} | cut -f3 -d ':')"
case "${DEST}" in
*.cpio.gz)
@@ -227,7 +256,7 @@ Defaults ()
SNAP_TYPE="ext2"
;;
*)
- Error "unrecognized resync string"
+ handle_error "unrecognized resync string"
;;
esac
@@ -250,31 +279,29 @@ Defaults ()
}
-Validate_input ()
+validate_input ()
{
- case "${SNAP_TYPE}" in
+ case "${SNAP_TYPE}" in
cpio|squashfs|jffs2|ext2|ext3)
;;
*)
- Error "invalid filesystem type \"${SNAP_TYPE}\""
+ handle_error "invalid filesystem type \"${SNAP_TYPE}\""
;;
esac
if [ ! -d "${SNAP_COW}" ]
then
- Error "${SNAP_COW} is not a directory"
+ handle_error "${SNAP_COW} is not a directory"
fi
if [ "$(id -u)" -ne 0 ]
then
- Error "you are not root"
+ handle_error "you are not root"
fi
}
-Mount_device ()
+mount_device ()
{
- mkdir -p "${MOUNTP}"
-
case "${SNAP_DEV}" in
"")
# create a temp
@@ -289,21 +316,61 @@ Mount_device ()
esac
}
-Do_snapshot ()
+do_filelist ()
+{
+ # BUGS: supports only cpio.gz types right now
+ TMP_FILELIST=$1
+ if [ -f "${SNAP_LIST}" ]
+ then
+ # Generate include list
+ #
+ for entry in $(cat "${SNAP_LIST}" | grep -v '^#.*$' | grep -v '^ *$')
+ do
+ if [ -f "${entry}" ]
+ then
+ printf "%s\000" "${entry}" >> "${TMP_FILELIST}"
+ elif [ -d "${entry}" ]
+ then
+ cd /
+ find "${entry}" -print0 >> "${TMP_FILELIST}"
+ cd $OLDPWD
+ fi
+ done
+ if [ "${SNAP_COW}" = "${DEF_SNAP_COW}" ]
+ then
+ # Relative to rootfs
+ echo "/"
+ else
+ # Mostly "/home"
+ echo "${SNAP_COW}"
+ fi
+ else
+ cd "${SNAP_COW}"
+ find . -path '*.wh.*' -prune -o -print0 >> "${TMP_FILELIST}"
+ cd $OLDPWD
+ echo "${SNAP_COW}"
+ fi
+}
+
+do_snapshot ()
{
+ TMP_FILELIST=$(mktemp -p /live "${TMP_FILELIST}.XXXXXX")
+
case "${SNAP_TYPE}" in
squashfs)
- EXCLUDE_LIST="$(mktemp -p ${SAFE_TMPDIR} live-snapshot-exclude-
list.XXXXXX)"
- echo "./${EXCLUDE_LIST}" > "${EXCLUDE_LIST}"
+ echo ".${TMP_FILELIST}" >"${TMP_FILELIST}"
+ # Removing whiteheads of unionfs
cd "${SNAP_COW}"
- find . -name '*.wh.*' >> "${EXCLUDE_LIST}"
+ find . -name '*.wh.*' >> "${TMP_FILELIST}"
cd "${OLDPWD}"
- mksquashfs "${SNAP_COW}" "${DEST}" -ef "${EXCLUDE_LIST}"
- rm -f "${EXCLUDE_LIST}"
+ mksquashfs "${SNAP_COW}" "${DEST}" -ef "${TMP_FILELIST}"
;;
cpio)
- ( cd "${SNAP_COW}" && find . -path '*.wh.*' -prune -o -print0 | cpio --
quiet -o0 -H newc | gzip -9c > "${DEST}" ) || exit 1
+ WORKING_DIR=$(do_filelist "${TMP_FILELIST}")
+ cd "${WORKING_DIR}"
+ cat "${TMP_FILELIST}" | cpio --quiet -o0 -H newc | gzip -9c > "${DEST}" )
|| exit 1
+ cd "${OLDPWD}"
;;
ext2|ext3)
@@ -316,9 +383,14 @@ Do_snapshot ()
mkfs.jffs2 --root="${SNAP_COW}" --output="${DEST}"
;;
esac
+
+ if [ -f "${TMP_FILELIST}" ]
+ then
+ rm -f "${TMP_FILELIST}"
+ fi
}
-Clean ()
+clean ()
{
if echo "${DEST}" | grep -q "${MOUNTP}"
then
@@ -329,14 +401,23 @@ Clean ()
fi
}
-Main ()
+main ()
{
- Parse_args "${@}"
- Defaults
- Validate_input
- trap 'Clean' EXIT
- Mount_device
- Do_snapshot
+ parse_args "${@}"
+ defaults
+ validate_input
+ trap 'clean' EXIT
+ mount_device
+ do_snapshot
+ if [ -z "${SNAP_RESYNC_STRING}" ]
+ then
+ echo "Please move ${DEST} (if is not already in it)" > /dev/null 1>&2
+ echo "in a supported writable partition (e.g ext3, vfat)." > /dev/null 1>&2
+ if grep -qv persistent /proc/cmdline
+ then
+ echo "Remember to boot this live system with \"persistent\" specified at
boot prompt." > /dev/null 1>&2
+ fi
+ fi
}
-Main "${@:-}"
+main "${@:-}"
diff --git a/conf/live-snapshot.list b/conf/live-snapshot.list
new file mode 100644
index 0000000..30fe29d
--- /dev/null
+++ b/conf/live-snapshot.list
@@ -0,0 +1,18 @@
+# /etc/live-snapshot resync list example
+#
+# If this file is present, each uncommented not empty line will be parsed
when
+# running live-snapshot and included in target snapshot.
+#
+# The syntax for the line is just a full file or directory pathname.
+# Those files and directories, and only those will be included on automatic
persistence handling.
+
+# Include itself for reuse
+/etc/live-snapshot.list
+
+# Include networking setups
+/etc/network/interfaces
+/etc/resolv.conf
+/etc/hosts
+
+# Include the whole Desktop directory of the default user
+/home/user/Desktop
diff --git a/manpages/live-snapshot.en.1.txt b/manpages/live-snapshot.en.1.txt
index e880b08..502acc8 100644
--- a/manpages/live-snapshot.en.1.txt
+++ b/manpages/live-snapshot.en.1.txt
@@ -55,6 +55,12 @@ the filename/label used for the output file/partition. If
left blank, live-snaps
internally used on resyncs.
+ -f, --refresh::
+
+try to do the same operation that should be done at reboot or halt, resyncing
+boot-time auto discovered snapshots. Useful to prevent a crash or surge
+power-off.
+
-t, --type **TYPE**::
Type could be one of "cpio", "squashfs", "ext2", "ext3" or "jffs2".
@@ -71,6 +77,14 @@ show usage and exit
output version information and exit
+Files
+-----
+
+ /etc/live-snapshot.list
+
+This optional file, if present changes the behaviour of live-snapshot, only
files and dirs listed there are included (integrally) in the snapshot.
+Beware, it is an experimental feature that only works for cpio targets now.
+
See also
--------
diff --git a/manpages/live-snapshot.it.1.txt b/manpages/live-snapshot.it.1.txt
index e396efe..fd1ac04 100644
--- a/manpages/live-snapshot.it.1.txt
+++ b/manpages/live-snapshot.it.1.txt
@@ -61,6 +61,12 @@ del device oppure user`a l'intera partizione.
usato internamente nelle sincronizzazioni dallo script di init di
live-initramfs. Il formato pu\`o cambiare, usatelo a vostro rischio.
+ -f, --refresh::
+
+scatena la stessa operazione che verrebbe fatta al reboot o all'halt della
+macchina, provando a fare il resync degli snapshot trovati al boot, usabile
+per salvare le modifiche in vista di un crash o di una mancanza di corrente.
+
-t, --type **TYPE**::
il tipo pu`o essere "cpio", "squashfs" o "ext2".
@@ -77,6 +83,15 @@ mostra l'utilizzo ed esce
da informazioni sulla versione ed esce
+Files
+-----
+
+ /etc/live-snapshot.list
+
+Facoltativo, se presente cambia completamente il funzionamento di live-
snapshot; solo i files e le directory elencate verranno effettivamente inclusi
nello snapshot.
+Attenzione, e` una funzionalita` sperimentale che funziona attualmente solo
con gli snapshot di tipo "cpio".
+
+
See also
--------
diff --git a/scripts/live b/scripts/live
index 0d84533..23e9dcb 100755
--- a/scripts/live
+++ b/scripts/live
@@ -832,7 +832,7 @@ try_snap ()
fi
else
# cpio.gz snapshot
- if ! (cd "${snap_mount}" && zcat "${snapback}/${snapfile}" | cpio -i -u -d
2>/dev/null)
+ if ! (cd "${snap_mount}" && zcat "${snapback}/${snapfile}" | cpio --
extract --preserve-modification-time --no-absolute-filenames --sparse --
unconditional --make-directories 2>/dev/null)
then
log_warning_msg "Impossible to include the ${snapfile} Snapshot"
return 1
diff --git a/scripts/live-helpers b/scripts/live-helpers
index 02c3e55..3c548f3 100644
--- a/scripts/live-helpers
+++ b/scripts/live-helpers
@@ -72,12 +72,9 @@ where_is_mounted ()
if grep -q "^${device} " /proc/mounts
then
- grep "^${device} " /proc/mounts | read d mountpoint rest
- echo ${mountpoint}
- return 0
+ # return the first found
+ grep "^${device} " /proc/mounts | cut -f2 -d ' '
fi
-
- return 1
}
lastline ()
@@ -120,9 +117,9 @@ fs_size ()
if [ -z "${mountp}" ]
then
- mountp=$(where_is_mounted "${dev}")
+ mountp="$(where_is_mounted ${dev})"
- if [ "${?}" -gt 0 ]
+ if [ -z "${mountp}" ]
then
mountp="/mnt/tmp_fs_size"
@@ -240,10 +237,12 @@ try_mount ()
mountp="${2}"
opts="${3}"
- if where_is_mounted ${dev} > /dev/null
+ old_mountp="$(where_is_mounted ${dev})"
+
+ if [ -n "${old_mountp}" ]
then
- mount -o remount,"${opts}" ${dev} $(where_is_mounted ${dev}) || panic
"Remounting failed"
- mount -o bind $(where_is_mounted ${dev}) ${mountp} || panic "Cannot bind-
mount"
+ mount -o remount,"${opts}" "${dev}" "${old_mountp}" || panic "Remounting
${dev} ${opts} on ${old_mountp} failed"
+ mount -o bind "${old_mountp}" "${mountp}" || panic "Cannot bind-mount
${old_mountp} on ${mountp}"
else
mount -t $(get_fstype "${dev}") -o "${opts}" "${dev}" "${mountp}" || panic
"Cannot mount ${dev} on ${mountp}"
fi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-New-live-snapshot-version.patch
Type: text/x-patch
Size: 15216 bytes
Desc: not available
Url : http://lists.alioth.debian.org/pipermail/debian-live-devel/attachments/20080601/b3bbb08d/attachment-0002.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: live-snapshot
Type: application/x-shellscript
Size: 9394 bytes
Desc: not available
Url : http://lists.alioth.debian.org/pipermail/debian-live-devel/attachments/20080601/b3bbb08d/attachment-0003.bin
Reply to: