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 <[EMAIL PROTECTED]> +# Copyright (C) 2006,2008 Marco Amadori <[EMAIL PROTECTED]> # Copyright (C) 2008 Chris Lamb <[EMAIL PROTECTED]> # # 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:" [EMAIL PROTECTED] + echo "${PROGRAM_NAME}: error:" [EMAIL PROTECTED] exit 1 } panic () { - Error [EMAIL PROTECTED] + handle_error [EMAIL PROTECTED] } -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 <[EMAIL PROTECTED]>" 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 "[EMAIL PROTECTED]" - Defaults - Validate_input - trap 'Clean' EXIT - Mount_device - Do_snapshot + parse_args "[EMAIL PROTECTED]" + 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
From 49a64b037a1e2958898a3a11c0c484a6e44fea14 Mon Sep 17 00:00:00 2001 From: Marco Amadori <[EMAIL PROTECTED]> Date: Tue, 27 May 2008 12:51:08 +0200 Subject: [PATCH 1/1] New live-snapshot version. * Included support for specifing a list of files/dirs to be resynced, although this feature is enabled only for the "cpio" snapshot type. Look at "/usr/share/doc/live-initramfs/examples/live-snapshot.list" for hints. * New "--refresh" target to explicit save status of boot-time auto-discovered snapshots without rebooting. Signed-off-by: Marco Amadori <[EMAIL PROTECTED]> --- Makefile | 3 +- bin/live-snapshot | 205 +++++++++++++++++++++++++++------------ conf/live-snapshot.list | 18 ++++ manpages/live-snapshot.en.1.txt | 14 +++ manpages/live-snapshot.it.1.txt | 15 +++ scripts/live | 2 +- scripts/live-helpers | 19 ++-- 7 files changed, 202 insertions(+), 74 deletions(-) create mode 100644 conf/live-snapshot.list 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 <[EMAIL PROTECTED]> +# Copyright (C) 2006,2008 Marco Amadori <[EMAIL PROTECTED]> # Copyright (C) 2008 Chris Lamb <[EMAIL PROTECTED]> # # 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:" [EMAIL PROTECTED] + echo "${PROGRAM_NAME}: error:" [EMAIL PROTECTED] exit 1 } panic () { - Error [EMAIL PROTECTED] + handle_error [EMAIL PROTECTED] } -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 <[EMAIL PROTECTED]>" 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 "[EMAIL PROTECTED]" - Defaults - Validate_input - trap 'Clean' EXIT - Mount_device - Do_snapshot + parse_args "[EMAIL PROTECTED]" + 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 -- 1.5.6.rc0
live-snapshot
Description: application/shellscript
_______________________________________________ debian-live-devel mailing list debian-live-devel@lists.alioth.debian.org http://lists.alioth.debian.org/mailman/listinfo/debian-live-devel