f90e563110d7bf9105b0f30cda8bd2b2a45de385
[live-boot-grml.git] / bin / casper-snapshot
1 #!/bin/sh
2
3 # casper-snapshot - utility to do Debian Live systems snapshots
4 #
5 #   This program mount a /tmpfs under ~/Desktop and save the /cow
6 #   filesystem in it for reusing in another session.
7 #
8 # Copyright (C) 2006 Marco Amadori <marco.amadori@gmail.com>
9 #
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #
24 # On Debian systems, the complete text of the GNU General Public License
25 # can be found in /usr/share/common-licenses/GPL file.
26
27 PROGRAM="`basename ${0}`"
28 VERSION=0.0.1
29
30 # Source casper conf
31 if [ -e /etc/casper.conf ]; then
32         . /etc/casper.conf
33 else
34         USERNAME=`cat /etc/passwd | grep "999" | cut -f1 -d ':'`
35 fi
36
37 Header ()
38 {
39         echo "${PROGRAM} - utility to do Debian Live snapshots"
40         echo
41         echo "Usage: ${PROGRAM} [-c|--cow DIRECTORY] [-d|--dest DIRECTORY] [-o|--output FILE] [-t|--type TYPE]"
42         echo "Usage: ${PROGRAM} [-h|--help]"
43         echo "Usage: ${PROGRAM} [-u|--usage]"
44         echo "Usage: ${PROGRAM} [-v|--version]"
45 }
46
47 Usage ()
48 {
49         MESSAGE=${1}
50         Header
51         echo
52         echo "Try \"${PROGRAM} --help\" for more information."
53         if [ ! -z "${MESSAGE}" ]; then
54                 echo -e "${MESSAGE}"
55                 exit 1
56         else
57                 exit 0
58         fi
59 }
60
61 Help ()
62 {
63         Header
64         echo
65         echo "Options:"
66         echo "  -c, --cow: specifies the copy on write directory (default: /cow)."
67         echo "  -d, --destination: specifies the output snapshot directory (default: /home/\$USERNAME/Desktop/casper-snapshot)."
68         echo "  -o, --output: specifies the output image file (default: $type dependent)."
69         echo "  -t,--type: specifies the snapshot type between \'squashfs\', \'ext2\' or \'cpio\'.gz archive (default: cpio)"
70         exit 0
71 }
72
73 Version ()
74 {
75         echo "${PROGRAM}, version ${VERSION}"
76         echo
77         echo "Copyright (C) 2006 Marco Amadori <marco.amadori@gmail.com>"
78         echo
79         echo "This program is free software; you can redistribute it and/or modify"
80         echo "it under the terms of the GNU General Public License as published by"
81         echo "the Free Software Foundation; either version 2 of the License, or"
82         echo "(at your option) any later version."
83         echo
84         echo "This program is distributed in the hope that it will be useful,"
85         echo "but WITHOUT ANY WARRANTY; without even the implied warranty of"
86         echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"
87         echo "GNU General Public License for more details."
88         echo
89         echo "You should have received a copy of the GNU General Public License"
90         echo "along with this program; if not, write to the Free Software"
91         echo "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA"
92         echo
93         echo "On Debian systems, the complete text of the GNU General Public License"
94         echo "can be found in /usr/share/common-licenses/GPL file."
95         echo
96         echo "Homepage: <http://live.debian.net/>"
97         exit 0
98 }
99
100 Do_snapshot ()
101 {
102         case "${TYPE}" in
103                 squashfs)
104                         echo "./tmp/exclude_list" > /tmp/exclude_list
105                         ( cd "${COW}" && find . -name '*.wh.*' >> /tmp/exclude_list )
106                         mksquashfs "${COW}" "${DEST}" -ef /tmp/exclude_list || exit 1
107                         rm /tmp/exclude_list
108                         ;;
109                 cpio)
110                         ( cd "${COW}" && find . -path '*.wh.*' -prune -o -print0 | cpio --quiet -o0 -H newc | gzip -9c > "${DEST}" ) || exit 1
111                         ;;
112                 ext2)
113                         DU_DIM="`du -ks ${COW} | cut -f1`"
114                         REAL_DIM="`expr ${DU_DIM} + ${DU_DIM} / 20`" # Just 5% more to be sure, need something more sophistcated here...
115                         genext2fs --size-in-blocks=${REAL_DIM} --reserved-blocks=0 --root="${COW}" "${DEST}" || exit 1
116                         ;;
117                 *)
118                         echo "Internal error."
119                         exit 1
120                         ;;
121         esac
122 }
123
124 Lastline()
125 {
126         while read lines ; do
127                 line=${lines}
128         done
129         echo "${line}"
130 }
131
132 Base_path ()
133 {
134         testpath="${1}"
135         mounts="`awk '{print $2}' /proc/mounts`"
136         testpath="`realpath ${testpath}`"
137
138         while true ; do
139                 if echo "${mounts}" | grep -qs "^${testpath}" ; then
140                         set -- `echo "${mounts}" | grep "^${testpath}" | Lastline`
141                         echo ${1}
142                         break
143                 else
144                         testpath=`dirname $testpath`
145                 fi
146         done
147 }
148
149 Is_same_mount ()
150 {
151         dir1="`Base_path ${1}`"
152         dir2="`Base_path ${2}`"
153         if [ "${dir1}" == "${dir2}" ]; then
154                 return 0
155         else
156                 return 1
157         fi
158 }
159
160 Parse_args ()
161 {
162         # Parse command line
163         ARGS="${1}"
164         ARGUMENTS="`getopt --longoptions cow:,destination:,output:,type:,help,usage,version --name=${PROGRAM} --options c:d:o:t:,h,u,v --shell sh -- ${ARGS}`"
165
166         if [ "${?}" != "0" ]; then
167                 echo "Terminating." >&2
168                 exit 1
169         fi
170
171         eval set -- "${ARGUMENTS}"
172
173         while true; do
174                 case "${1}" in
175                         -c|--cow)
176                                 SNAP_COW="${2}"; shift 2 ;;
177                         -d|--destination)
178                                 SNAP_DEST="${2}"; shift 2 ;;
179                         -o|--output)
180                                 SNAP_OUTPUT="${2}"; shift 2 ;;
181                         -t|--type)
182                                 SNAP_TYPE="${2}"; shift 2 ;;
183                         -h|--help)
184                                 Help; shift ;;
185                         -u|--usage)
186                                 Usage ; shift ;;
187                         -v|--version)
188                                 Version; shift ;;
189                         --)
190                                 shift; break ;;
191                         *)
192                                 echo "Internal error."; exit 1 ;;
193                 esac
194         done
195 }
196
197 Defaults ()
198 {
199         DEF_COW="/cow"
200
201         # Bad options handling
202         if [ -z "${SNAP_COW}" ]; then
203                 COW="${DEF_COW}"
204         else
205                 COW="${SNAP_COW}"
206         fi
207         if [ ! -d "${COW}" ]; then
208                 Usage "Error: ${COW} is not a directory"
209         fi
210
211         case "${SNAP_TYPE}" in
212                 "cpio"|"squashfs"|"ext2")
213                         TYPE="${SNAP_TYPE}"
214                         ;;
215                 "")
216                         TYPE="cpio" ;;
217                 *)
218                         Usage "Error: unrecognized snapshot type"
219                         ;;
220         esac
221         
222         #if [ -d 
223         #if Is_same_mount 
224
225 }
226
227 Main ()
228 {
229         Parse_args "${@}"
230         Defaults
231         Do_snapshot
232 }
233
234 Main "${@}"