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