3 # live-snapshot - utility to manage Debian Live systems snapshots
5 # This program mounts a device (fallback to /tmpfs under $MOUNTP
6 # and saves the /live/cow (or a different directory) filesystem in it
7 # for reuse in another live-initramfs session.
8 # Look at the manpage for more informations.
10 # Copyright (C) 2006-2008 Marco Amadori <marco.amadori@gmail.com>
11 # Copyright (C) 2008 Chris Lamb <chris@chris-lamb.co.uk>
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 # On Debian systems, the complete text of the GNU General Public License
27 # can be found in /usr/share/common-licenses/GPL-3 file.
29 # declare here two vars from /etc/live.conf because of "set -u"
33 if [ -n "${LIVE_SNAPSHOT_CHECK_UNBOUND}" ]
40 . /usr/share/initramfs-tools/scripts/live-helpers
42 LIVE_CONF="/etc/live.conf"
45 export USERNAME USERFULLNAME HOSTNAME
48 PROGRAM=$(basename "${EXECUTABLE}")
50 # Needs to be available at run and reboot time
53 # Permits multiple runs
54 MOUNTP="$(mktemp -d -p ${SAFE_TMPDIR} live-snapshot-mnt.XXXXXX)"
55 DEST="${MOUNTP}/live-sn.cpio.gz"
56 DEF_SNAP_COW="/live/cow"
57 TMP_FILELIST="${PROGRAM}.list"
59 # Command line defaults and declarations
60 SNAP_COW="${DEF_SNAP_COW}"
65 SNAP_LIST="/etc/live-snapshot.list"
69 echo "${PROGRAM}: error:" ${@}
80 echo "${PROGRAM} - utility to perform snapshots of Debian Live systems"
82 echo "usage: ${PROGRAM} [-c|--cow DIRECTORY] [-d|--device DEVICE] [-o|--output FILE] [-t|--type TYPE]"
83 echo " ${PROGRAM} [-r|--resync-string STRING]"
84 echo " ${PROGRAM} [-f|--refresh]"
85 echo " ${PROGRAM} [-h|--help]"
86 echo " ${PROGRAM} [-u|--usage]"
87 echo " ${PROGRAM} [-v|--version]"
96 echo " -c, --cow: copy on write directory (default: ${SNAP_COW})."
97 echo " -d, --device: output snapshot device (default: ${SNAP_DEV:-auto})."
98 echo " -o, --output: output image file (default: ${DEST})."
99 echo " -r, --resync-string: internally used to resync previous made snapshots."
100 echo " -f, --refresh: try to sync a running snapshot."
101 echo " -t, --type: snapshot filesystem type. Options: \"squashfs\", \"ext2\", \"ext3\", \"jffs2\" or \"cpio\".gz archive (default: ${SNAP_TYPE})"
103 echo "Look at live-snapshot(1) man page for more information."
113 echo "Try \"${PROGRAM} --help\" for more information."
122 echo "Copyright (C) 2006 Marco Amadori <marco.amadori@gmail.com>"
123 echo "Copyright (C) 2008 Chris Lamb <chris@chris-lamb.co.uk>"
125 echo "This program is free software; you can redistribute it and/or modify"
126 echo "it under the terms of the GNU General Public License as published by"
127 echo "the Free Software Foundation; either version 2 of the License, or"
128 echo "(at your option) any later version."
130 echo "This program is distributed in the hope that it will be useful,"
131 echo "but WITHOUT ANY WARRANTY; without even the implied warranty of"
132 echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"
133 echo "GNU General Public License for more details."
135 echo "You should have received a copy of the GNU General Public License"
136 echo "along with this program; if not, write to the Free Software"
137 echo "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA"
139 echo "On Debian systems, the complete text of the GNU General Public License"
140 echo "can be found in /usr/share/common-licenses/GPL-2 file."
142 echo "Homepage: <http://debian-live.alioth.debian.org/>"
150 if [ -n "${ROOTSNAP}" ]; then
151 "${EXECUTABLE}" --resync-string="${ROOTSNAP}"
155 if [ -n "${HOMESNAP}" ]; then
156 "${EXECUTABLE}" --resync-string="${HOMESNAP}"
162 echo "No autoconfigured snapshots found at boot;" > /dev/null 1>&2
163 echo "(no resync string in ${LIVE_CONF})." > /dev/null 1>&2
172 ARGUMENTS="$(getopt --longoptions cow:,device:,output,resync-string:,refresh,type:,help,usage,version --name=${PROGRAM} --options c:d:o:t:r:fhuv --shell sh -- ${ARGS})"
174 eval set -- "${ARGUMENTS}"
200 SNAP_RESYNC_STRING="${2}"
227 Error "internal error."
236 # Parse resync string
237 if [ -n "${SNAP_RESYNC_STRING}" ]
239 SNAP_COW=$(echo "${SNAP_RESYNC_STRING}" | cut -f1 -d ':')
240 SNAP_DEV=$(echo "${SNAP_RESYNC_STRING}" | cut -f2 -d ':')
241 DEST="${MOUNTP}/$(echo ${SNAP_RESYNC_STRING} | cut -f3 -d ':')"
260 Error "unrecognized resync string"
263 elif [ -z "${SNAP_OUTPUT}" ]
265 # Set target file based on image
266 case "${SNAP_TYPE}" in
268 DEST="${MOUNTP}/live-sn.cpio.gz"
272 DEST="${MOUNTP}/live-sn.${SNAP_TYPE}"
276 DEST="${MOUNTP}/live-sn.ext2"
280 DEST="${SNAP_OUTPUT}"
286 case "${SNAP_TYPE}" in
287 cpio|squashfs|jffs2|ext2|ext3)
291 Error "invalid filesystem type \"${SNAP_TYPE}\""
295 if [ ! -d "${SNAP_COW}" ]
297 Error "${SNAP_COW} is not a directory"
300 if [ "$(id -u)" -ne 0 ]
302 Error "you are not root"
308 case "${SNAP_DEV}" in
311 mount -t tmpfs -o rw tmpfs "${MOUNTP}"
315 if [ -b "${SNAP_DEV}" ]
317 try_mount "${SNAP_DEV}" "${MOUNTP}" rw
325 # Returns true if file exists and it is also present in "cow" directory
326 # This means it is modified in respect to read-only media, so it deserve
331 if [ -e "${entry}" ] || [ -L "${entry}" ]
333 if [ -e "${DEF_SNAP_COW}/${entry}" ] || [ -L "${DEF_SNAP_COW}/${entry}" ]
343 # BUGS: supports only cpio.gz types, and do not handle deleted files yet
346 if [ -f "${SNAP_LIST}" ]
348 # Generate include list
349 for entry in $(cat "${SNAP_LIST}" | grep -v '^#.*$' | grep -v '^ *$')
354 find "${entry}" | while read line
356 if Entry_is_modified "${line}"
358 printf "%s\000" "${line}" >> "${TMP_FILELIST}"
362 elif Entry_is_modified "${entry}"
364 # if file exists and it is modified
365 printf "%s\000" "${entry}" >> "${TMP_FILELIST}"
369 if [ "${SNAP_COW}" = "${DEF_SNAP_COW}" ]
379 find . -path '*.wh.*' -prune -o -print0 >> "${TMP_FILELIST}"
387 TMP_FILELIST=$(mktemp -p "${SAFE_TMPDIR}" "${TMP_FILELIST}.XXXXXX")
389 case "${SNAP_TYPE}" in
391 echo ".${TMP_FILELIST}" > "${TMP_FILELIST}"
392 # Removing whiteheads of unionfs
394 find . -name '*.wh.*' >> "${TMP_FILELIST}"
396 mksquashfs "${SNAP_COW}" "${DEST}" -ef "${TMP_FILELIST}"
400 WORKING_DIR=$(Do_filelist "${TMP_FILELIST}")
402 cat "${TMP_FILELIST}" | cpio --quiet -o0 -H newc | gzip -9c > "${DEST}" || exit 1
407 DU_DIM="$(du -ks ${SNAP_COW} | cut -f1)"
408 REAL_DIM="$(expr ${DU_DIM} + ${DU_DIM} / 20)" # Just 5% more to be sure, need something more sophistcated here...
409 genext2fs --size-in-blocks=${REAL_DIM} --reserved-percentage=0 --root="${SNAP_COW}" "${DEST}"
413 mkfs.jffs2 --root="${SNAP_COW}" --output="${DEST}"
417 if [ -f "${TMP_FILELIST}" ]
419 rm -f "${TMP_FILELIST}"
425 if [ -z "${SNAP_RESYNC_STRING}" ] && echo "${DEST}" | grep -q "${MOUNTP}"
427 echo "${DEST} is present on ${MOUNTP}, therefore no automatic unmounting the latter." > /dev/null 1>&2
436 if [ -z "${SNAP_RESYNC_STRING}" ]
440 echo "Please move ${DEST} (if is not already in it)" > /dev/null 1>&2
441 echo "in a supported writable partition (e.g ext3, vfat)." > /dev/null 1>&2
445 echo "To use ${DEST} you need to rebuild your media or add it" > /dev/null 1>&2
446 echo "to your multisession disc under the \"/live\" directory." > /dev/null 1>&2
450 echo "Please cat or flashcp ${DEST} to your partition in order to start using it." > /dev/null 1>&2
454 if grep -qv persistent /proc/cmdline
456 echo "Remember to boot this live system with \"persistent\" specified at boot prompt." > /dev/null 1>&2