141d266786cd3cb08046969a009a5de451c3ce99
[live-boot-grml.git] / bin / live-snapshot
1 #!/bin/sh
2
3 # live-snapshot - utility to manage Debian Live systems snapshots
4 #
5 #   This program mount a device (fallback to /tmpfs under /mnt/snapshot
6 #   and save the /live/cow (or a different dir) filesystem in it for reusing
7 #   in another live-initramfs session. Look at manpage for more info.
8 #
9 # Copyright (C) 2006 Marco Amadori <marco.amadori@gmail.com>
10 # Copyright (C) 2008 Chris Lamb <chris@chris-lamb.co.uk>
11 #
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #
26 # On Debian systems, the complete text of the GNU General Public License
27 # can be found in /usr/share/common-licenses/GPL-2 file.
28
29 set -eu
30
31 . /usr/share/initramfs-tools/scripts/live-helpers
32 . /etc/live.conf
33
34 export USERNAME USERFULLNAME HOSTNAME
35
36 PROGRAM="$(basename $0)"
37 VERSION=0.0.2
38
39 MOUNTP="/mnt/live-snapshot"
40 SNAP_COW="/live/cow"
41 SNAP_DEV=""
42 DEST="${MOUNTP}/live-sn.cpio.gz"
43 SNAP_TYPE="cpio"
44 DESKTOP_LINK="/home/${USERNAME}/Desktop/live-snapshot"
45 SNAP_RESYNC_STRING=""
46
47 Error ()
48 {
49         echo "${PROGRAM}: error:" ${@}
50         exit 1
51 }
52
53 panic ()
54 {
55         Error ${@}
56 }
57
58 Header ()
59 {
60         echo "${PROGRAM} - utility to perform snapshots of Debian Live systems"
61         echo
62         echo "usage: ${PROGRAM} [-c|--cow DIRECTORY] [-d|--device DEVICE] [-o|--output FILE] [-t|--type TYPE]"
63         echo "       ${PROGRAM} [-r|--resync-string STRING]"
64         echo "       ${PROGRAM} [-h|--help]"
65         echo "       ${PROGRAM} [-u|--usage]"
66         echo "       ${PROGRAM} [-v|--version]"
67 }
68
69 Help ()
70 {
71         Header
72
73         echo
74         echo "Options:"
75         echo "  -c, --cow: copy on write directory (default: ${SNAP_COW})."
76         echo "  -d, --device: output snapshot device (default: ${SNAP_DEV:-auto})."
77         echo "  -o, --output: output image file (default: ${DEST})."
78         echo "  -r, --resync-string: internally used to resync previous made snapshots."
79         echo "  -t, --type: snapshot filesystem type. Options: \"squashfs\", \"ext2\", \"ext3\", \"jffs2\" or \"cpio\".gz archive (default: ${SNAP_TYPE})"
80         echo
81         echo "Look at live-snapshot(1) man page for more information."
82
83         exit 0
84 }
85
86 Usage ()
87 {
88         Header
89
90         echo
91         echo "Try \"${PROGRAM} --help\" for more information."
92
93         exit 0
94 }
95         
96
97 Version ()
98 {
99         echo "${PROGRAM}, version ${VERSION}"
100         echo
101         echo "Copyright (C) 2006 Marco Amadori <marco.amadori@gmail.com>"
102         echo
103         echo "This program is free software; you can redistribute it and/or modify"
104         echo "it under the terms of the GNU General Public License as published by"
105         echo "the Free Software Foundation; either version 2 of the License, or"
106         echo "(at your option) any later version."
107         echo
108         echo "This program is distributed in the hope that it will be useful,"
109         echo "but WITHOUT ANY WARRANTY; without even the implied warranty of"
110         echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"
111         echo "GNU General Public License for more details."
112         echo
113         echo "You should have received a copy of the GNU General Public License"
114         echo "along with this program; if not, write to the Free Software"
115         echo "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA"
116         echo
117         echo "On Debian systems, the complete text of the GNU General Public License"
118         echo "can be found in /usr/share/common-licenses/GPL-2 file."
119         echo
120         echo "Homepage: <http://debian-live.alioth.debian.org/>"
121
122         exit 0
123 }
124
125 Is_same_mount ()
126 {
127         dir1="$(Base_path ${1})"
128         dir2="$(Base_path ${2})"
129
130         if [ "${dir1}" = "${dir2}" ]
131         then
132                 return 0
133         else
134                 return 1
135         fi
136 }
137
138 Parse_args ()
139 {
140         # Parse command line
141         ARGS="${*}"
142         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})"
143
144         eval set -- "${ARGUMENTS}"
145
146         while true
147         do
148                 case "${1}" in
149                         -c|--cow)
150                                 SNAP_COW="${2}"
151                                 shift 2
152                                 ;;
153
154                         -d|--device)
155                                 SNAP_DEV="${2}"
156                                 shift 2
157                                 ;;
158
159                         -o|--output)
160                                 SNAP_OUTPUT="${2}"
161                                 shift 2
162                                 ;;
163
164                         -t|--type)
165                                 SNAP_TYPE="${2}"
166                                 shift 2
167                                 ;;
168
169                         -r|--resync-string)
170                                 SNAP_RESYNC_STRING="${2}"
171                                 break
172                                 ;;
173
174                         -h|--help)
175                                 Help
176                                 ;;
177
178                         -u|--usage)
179                                 Usage
180                                 ;;
181
182                         -v|--version)
183                                 Version
184                                 ;;
185
186                         --)
187                                 shift
188                                 break
189                                 ;;
190
191                         *)
192                                 Error "internal error."
193                                 ;;
194
195                 esac
196         done
197
198 }
199
200 Defaults ()
201 {
202         # Parse resync string
203         if [ -n "${SNAP_RESYNC_STRING}" ]
204         then
205                 SNAP_COW=$(echo "${SNAP_RESYNC_STRING}" | cut -f1 -d ':')
206                 SNAP_DEV=$(echo "${SNAP_RESYNC_STRING}" | cut -f2 -d ':')
207                 DEST=$(echo "${SNAP_RESYNC_STRING}" | cut -f3 -d ':')
208
209                 case "${DEST}" in
210                         *.cpio.gz)
211                                 SNAP_TYPE="cpio"
212                                 ;;
213
214                         *.squashfs)
215                                 SNAP_TYPE="squashfs"
216                                 ;;
217
218                         *.jffs2)
219                                 SNAP_TYPE="jffs2"
220                                 ;;
221
222                         ""|*.ext2|*.ext3)
223                                 SNAP_TYPE="ext2"
224                                 ;;
225                         *)
226                                 Error "unrecognized resync string"
227                                 ;;
228                 esac
229
230         else
231                 # Set target file based on image
232                 case "${SNAP_TYPE}" in
233                         cpio)
234                                 DEST="${MOUNTP}/live-sn.cpio.gz"
235                                 ;;
236
237                         squashfs|jffs2|ext2)
238                                 DEST="${MOUNTP}/live-sn.${SNAP_TYPE}"
239                                 ;;
240
241                         ext3)
242                                 DEST="${MOUNTP}/live-sn.ext2"
243                                 ;;
244                 esac
245         fi
246
247 }
248
249 Validate_input ()
250 {
251         case "${SNAP_TYPE}" in 
252                 cpio|squashfs|jffs2|ext2|ext3)
253                         ;;
254                 *)
255                         Error "invalid filesystem type \"${SNAP_TYPE}\""
256                         ;;
257         esac
258
259         if [ ! -d "${SNAP_COW}" ]
260         then
261                 Error "${SNAP_COW} is not a directory"
262         fi
263
264         if [ "$(id -u)" -ne 0 ]
265         then
266                 Error "you are not root"
267         fi
268 }
269
270 Mount_device ()
271 {
272         mkdir -p "${MOUNTP}"
273
274         case "${SNAP_DEV}" in
275                 "")
276                         # create a temp
277                         mount -t tmpfs -o rw tmpfs "${MOUNTP}"
278                         ;;
279                 *)
280                         if [ -b "${SNAP_DEV}" ]
281                         then
282                                 try_mount "${SNAP_DEV}" "${MOUNTP}" rw
283                         fi
284                         ;;
285         esac
286 }
287
288 Do_snapshot ()
289 {
290         case "${SNAP_TYPE}" in
291                 squashfs)
292                         echo "./tmp/exclude_list" > /tmp/exclude_list
293                         ( cd "${SNAP_COW}" && find . -name '*.wh.*' >> /tmp/exclude_list )
294                         mksquashfs "${SNAP_COW}" "${DEST}" -ef /tmp/exclude_list
295                         rm /tmp/exclude_list
296                         ;;
297
298                 cpio)
299                         ( cd "${SNAP_COW}" && find . -path '*.wh.*' -prune -o -print0 | cpio --quiet -o0 -H newc | gzip -9c > "${DEST}" ) || exit 1
300                         ;;
301
302                 ext2|ext3)
303                         DU_DIM="$(du -ks ${SNAP_COW} | cut -f1)"
304                         REAL_DIM="$(expr ${DU_DIM} + ${DU_DIM} / 20)" # Just 5% more to be sure, need something more sophistcated here...
305                         genext2fs --size-in-blocks=${REAL_DIM} --reserved-blocks=0 --root="${SNAP_COW}" "${DEST}"
306                         ;;
307
308                 jffs2)
309                         mkfs.jffs2 --root="${SNAP_COW}" --output="${DEST}"
310                         ;;
311         esac
312 }
313
314 Clean ()
315 {
316         umount "${MOUNTP}"
317         rmdir "${MOUNTP}"
318 }
319
320 Main ()
321 {
322         Parse_args "${@}"
323         Defaults
324         Validate_input
325         trap 'Clean' EXIT 
326         Mount_device
327         Do_snapshot
328 }
329
330 Main "${@:-}"