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