[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: