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