568fda73b4b05179bd858e5c9897183aed9b0d5c
[live-boot-grml.git] / scripts / boot / snapshot.sh
1 #!/bin/sh
2
3 #set -e
4
5 do_snap_copy ()
6 {
7         fromdev="${1}"
8         todir="${2}"
9         snap_type="${3}"
10         size=$(fs_size "${fromdev}" "" "used")
11
12         if [ -b "${fromdev}" ]
13         then
14                 log_success_msg "Copying snapshot ${fromdev} to ${todir}..."
15
16                 # look for free mem
17                 if [ -n "${HOMEMOUNTED}" -a "${snap_type}" = "HOME" ]
18                 then
19                         todev=$(awk -v pat="$(base_path ${todir})" '$2 == pat { print $1 }' /proc/mounts)
20                         freespace=$(df -k | awk '/'${todev}'/{print $4}')
21                 else
22                         freespace=$(awk '/^MemFree:/{f=$2} /^Cached:/{c=$2} END{print f+c}' /proc/meminfo)
23                 fi
24
25                 tomount="/mnt/tmpsnap"
26
27                 if [ ! -d "${tomount}" ]
28                 then
29                         mkdir -p "${tomount}"
30                 fi
31
32                 fstype=$(get_fstype "${fromdev}")
33
34                 if [ -n "${fstype}" ]
35                 then
36                         # Copying stuff...
37                         mount -o ro -t "${fstype}" "${fromdev}" "${tomount}" || log_warning_msg "Error in mount -t ${fstype} -o ro ${fromdev} ${tomount}"
38                         cp -a "${tomount}"/* ${todir}
39                         umount "${tomount}"
40                 else
41                         log_warning_msg "Unrecognized fstype: ${fstype} on ${fromdev}:${snap_type}"
42                 fi
43
44                 rmdir "${tomount}"
45
46                 if echo ${fromdev} | grep -qs loop
47                 then
48                         losetup -d "${fromdev}"
49                 fi
50
51                 return 0
52         else
53                 log_warning_msg "Unable to find the snapshot ${snap_type} medium"
54                 return 1
55         fi
56 }
57
58 try_snap ()
59 {
60         # copy the contents of previously found snapshot to ${snap_mount}
61         # and remember the device and filename for resync on exit in live-boot.init
62
63         snapdata="${1}"
64         snap_mount="${2}"
65         snap_type="${3}"
66         snap_relpath="${4}"
67
68         if [ -z "${snap_relpath}" ]
69         then
70                 # root snapshot, default usage
71                 snap_relpath="/"
72         else
73                 # relative snapshot (actually used just for "/home" snapshots)
74                 snap_mount="${2}${snap_relpath}"
75         fi
76
77         if [ -n "${snapdata}" ] && [ ! -b "${snapdata}" ]
78         then
79                 log_success_msg "found snapshot: ${snapdata}"
80                 snapdev="$(echo ${snapdata} | cut -f1 -d ' ')"
81                 snapback="$(echo ${snapdata} | cut -f2 -d ' ')"
82                 snapfile="$(echo ${snapdata} | cut -f3 -d ' ')"
83
84                 if ! try_mount "${snapdev}" "${snapback}" "ro"
85                 then
86                         break
87                 fi
88
89                 RES="0"
90
91                 if echo "${snapfile}" | grep -qs '\(squashfs\|ext2\|ext3\|ext4\|jffs2\)'
92                 then
93                         # squashfs, jffs2 or ext2/ext3/ext4 snapshot
94                         dev=$(get_backing_device "${snapback}/${snapfile}")
95
96                         do_snap_copy "${dev}" "${snap_mount}" "${snap_type}"
97                         RES="$?"
98                 else
99                         # cpio.gz snapshot
100
101                         # Unfortunately klibc's cpio is incompatible with the
102                         # rest of the world; everything else requires -u -d,
103                         # while klibc doesn't implement them. Try to detect
104                         # whether it's in use.
105                         cpiopath="$(which cpio)" || true
106                         if [ "$cpiopath" ] && grep -aq /lib/klibc "$cpiopath"
107                         then
108                                 cpioargs=
109                         else
110                                 cpioargs='--unconditional --make-directories'
111                         fi
112
113                         if [ -s "${snapback}/${snapfile}" ]
114                         then
115                                 BEFOREDIR="$(pwd)"
116                                 cd "${snap_mount}" && zcat "${snapback}/${snapfile}" | $cpiopath $cpioargs --extract --preserve-modification-time --no-absolute-filenames --sparse 2>/dev/null
117                                 RES="$?"
118                                 cd "${BEFOREDIR}"
119                         else
120                                 log_warning_msg "${snapback}/${snapfile} is empty, adding it for sync on reboot."
121                                 RES="0"
122                         fi
123
124                         if [ "${RES}" != "0" ]
125                         then
126                                 log_warning_msg "failure to \"zcat ${snapback}/${snapfile} | $cpiopath $cpioargs --extract --preserve-modification-time --no-absolute-filenames --sparse\""
127                         fi
128                 fi
129
130                 umount "${snapback}" ||  log_warning_msg "failure to \"umount ${snapback}\""
131
132                 if [ "${RES}" != "0" ]
133                 then
134                         log_warning_msg "Impossible to include the ${snapfile} Snapshot file"
135                 fi
136
137         elif [ -b "${snapdata}" ]
138         then
139                 # Try to find if it could be a snapshot partition
140                 dev="${snapdata}"
141                 log_success_msg "found snapshot ${snap_type} device on ${dev}"
142                 if echo "${dev}" | grep -qs loop
143                 then
144                         # strange things happens, user confused?
145                         snaploop=$( losetup ${dev} | awk '{print $3}' | tr -d '()' )
146                         snapfile=$(basename ${snaploop})
147                         snapdev=$(awk -v pat="$( dirname ${snaploop})" '$2 == pat { print $1 }' /proc/mounts)
148                 else
149                         snapdev="${dev}"
150                 fi
151
152                 if ! do_snap_copy "${dev}" "${snap_mount}" "${snap_type}"
153                 then
154                         log_warning_msg "Impossible to include the ${snap_type} Snapshot (i)"
155                         return 1
156                 else
157                         if [ -n "${snapfile}" ]
158                         then
159                                 # it was a loop device, user confused
160                                 umount ${snapdev}
161                         fi
162                 fi
163         else
164                 log_warning_msg "Impossible to include the ${snap_type} Snapshot (o)"
165                 return 1
166         fi
167
168         if [ -z ${PERSISTENCE_READONLY} ]
169         then
170                 echo "export ${snap_type}SNAP=${snap_relpath}:${snapdev}:${snapfile}" >> snapshot.conf # for resync on reboot/halt
171         fi
172         return 0
173 }