Removing useless whitespaces and empty lines.
[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 Version ()
100 {
101         echo "${PROGRAM}"
102         echo
103         echo "Copyright (C) 2006 Marco Amadori <marco.amadori@gmail.com>"
104         echo
105         echo "This program is free software; you can redistribute it and/or modify"
106         echo "it under the terms of the GNU General Public License as published by"
107         echo "the Free Software Foundation; either version 2 of the License, or"
108         echo "(at your option) any later version."
109         echo
110         echo "This program is distributed in the hope that it will be useful,"
111         echo "but WITHOUT ANY WARRANTY; without even the implied warranty of"
112         echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"
113         echo "GNU General Public License for more details."
114         echo
115         echo "You should have received a copy of the GNU General Public License"
116         echo "along with this program; if not, write to the Free Software"
117         echo "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA"
118         echo
119         echo "On Debian systems, the complete text of the GNU General Public License"
120         echo "can be found in /usr/share/common-licenses/GPL-2 file."
121         echo
122         echo "Homepage: <http://debian-live.alioth.debian.org/>"
123
124         exit 0
125 }
126
127 Is_same_mount ()
128 {
129         dir1="$(Base_path ${1})"
130         dir2="$(Base_path ${2})"
131
132         if [ "${dir1}" = "${dir2}" ]
133         then
134                 return 0
135         else
136                 return 1
137         fi
138 }
139
140 Parse_args ()
141 {
142         # Parse command line
143         ARGS="${*}"
144         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})"
145
146         eval set -- "${ARGUMENTS}"
147
148         while true
149         do
150                 case "${1}" in
151                         -c|--cow)
152                                 SNAP_COW="${2}"
153                                 shift 2
154                                 ;;
155
156                         -d|--device)
157                                 SNAP_DEV="${2}"
158                                 shift 2
159                                 ;;
160
161                         -o|--output)
162                                 SNAP_OUTPUT="${2}"
163                                 shift 2
164                                 ;;
165
166                         -t|--type)
167                                 SNAP_TYPE="${2}"
168                                 shift 2
169                                 ;;
170
171                         -r|--resync-string)
172                                 SNAP_RESYNC_STRING="${2}"
173                                 break
174                                 ;;
175
176                         -h|--help)
177                                 Help
178                                 ;;
179
180                         -u|--usage)
181                                 Usage
182                                 ;;
183
184                         -v|--version)
185                                 Version
186                                 ;;
187
188                         --)
189                                 shift
190                                 break
191                                 ;;
192
193                         *)
194                                 Error "internal error."
195                                 ;;
196
197                 esac
198         done
199 }
200
201 Defaults ()
202 {
203         # Parse resync string
204         if [ -n "${SNAP_RESYNC_STRING}" ]
205         then
206                 SNAP_COW=$(echo "${SNAP_RESYNC_STRING}" | cut -f1 -d ':')
207                 SNAP_DEV=$(echo "${SNAP_RESYNC_STRING}" | cut -f2 -d ':')
208                 DEST=$(echo "${SNAP_RESYNC_STRING}" | cut -f3 -d ':')
209
210                 case "${DEST}" in
211                         *.cpio.gz)
212                                 SNAP_TYPE="cpio"
213                                 ;;
214
215                         *.squashfs)
216                                 SNAP_TYPE="squashfs"
217                                 ;;
218
219                         *.jffs2)
220                                 SNAP_TYPE="jffs2"
221                                 ;;
222
223                         ""|*.ext2|*.ext3)
224                                 SNAP_TYPE="ext2"
225                                 ;;
226                         *)
227                                 Error "unrecognized resync string"
228                                 ;;
229                 esac
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 Validate_input ()
249 {
250         case "${SNAP_TYPE}" in
251                 cpio|squashfs|jffs2|ext2|ext3)
252                         ;;
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                 *)
281                         if [ -b "${SNAP_DEV}" ]
282                         then
283                                 try_mount "${SNAP_DEV}" "${MOUNTP}" rw
284                         fi
285                         ;;
286         esac
287 }
288
289 Do_snapshot ()
290 {
291         case "${SNAP_TYPE}" in
292                 squashfs)
293                         EXCLUDE_LIST="$(mktemp -p ${SAFE_TMPDIR} live-snapshot-exclude-list.XXXXXX)"
294                         echo "./${EXCLUDE_LIST}" > "${EXCLUDE_LIST}"
295                         cd "${SNAP_COW}"
296                         find . -name '*.wh.*' >> "${EXCLUDE_LIST}"
297                         cd "${OLDPWD}"
298                         mksquashfs "${SNAP_COW}" "${DEST}" -ef "${EXCLUDE_LIST}"
299                         rm -f "${EXCLUDE_LIST}"
300                         ;;
301
302                 cpio)
303                         ( cd "${SNAP_COW}" && find . -path '*.wh.*' -prune -o -print0 | cpio --quiet -o0 -H newc | gzip -9c > "${DEST}" ) || exit 1
304                         ;;
305
306                 ext2|ext3)
307                         DU_DIM="$(du -ks ${SNAP_COW} | cut -f1)"
308                         REAL_DIM="$(expr ${DU_DIM} + ${DU_DIM} / 20)" # Just 5% more to be sure, need something more sophistcated here...
309                         genext2fs --size-in-blocks=${REAL_DIM} --reserved-percentage=0 --root="${SNAP_COW}" "${DEST}"
310                         ;;
311
312                 jffs2)
313                         mkfs.jffs2 --root="${SNAP_COW}" --output="${DEST}"
314                         ;;
315         esac
316 }
317
318 Clean ()
319 {
320         if echo "${DEST}" | grep -q "${MOUNTP}"
321         then
322                 echo "${DEST} is present on ${MOUNTP}, therefore no automatic unmounting the latter." > /dev/null 1>&2
323         else
324                 umount "${MOUNTP}"
325                 rmdir "${MOUNTP}"
326         fi
327 }
328
329 Main ()
330 {
331         Parse_args "${@}"
332         Defaults
333         Validate_input
334         trap 'Clean' EXIT
335         Mount_device
336         Do_snapshot
337 }
338
339 Main "${@:-}"