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