5
VALID_FORMATS=( auto img-tar root-image root-image-gz root-tar squashfs-image
8
error() { echo "$@" 1>&2; }
9
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
13
Usage: ${0##*/} [ options ] source-image output-squash-image
15
convert 'source-image' into a squashfs filesystem image.
17
source-image is a file in one of:
20
output-squash-image will be a squashfs image.
23
-v | --verbose increase verbosity
24
-f | --format F source-image is of format F. default: auto.
26
auto: determine based on file and name heuristics
27
img-tar: tarball of root image (image file named .img)
28
root-image: filesytem (ext[234] in a file)
29
root-image-gz: root-image that is compressed with gzip
30
root-tar: tarball of / (supports .tar.xz .tar.gz)
31
squashfs-image: a squahsfs image (.squashfs)
32
-O | --owner O change ownership of output to O (user:group)
35
${0##*/} --format=my.tar.gz my.squashfs
39
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
41
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
45
local level="$1"; shift;
46
[ "${level}" -gt "${VERBOSITY}" ] && return
47
error "$(date -R):" "$@"
51
local level=${1}; shift;
52
[ "${level}" -gt "${VERBOSITY}" ] && return
57
#inargs(needle, [haystack])
58
# return true if needle is in haystack
59
local needle="$1" i=""
62
[ "$i" = "$needle" ] && return 0
68
# given 'img' (image.tar.gz), extract it and put the .img file in 'out'
69
local img="$1" out="$2" tempd="$3"
70
local mtmp=$(mktemp -d "${tempd}/img_from_tar.XXXXXX")
71
tar -C "$mtmp" -Sxf "$img" ||
72
{ error "failed to extract $img"; return 1; }
74
for f in "${mtmp}/"*; do
75
[ ! -f "$f" -o "${f%.img}" = "$f" ] && continue
77
{ error "multiple .img found in $img"; return 1; }
80
[ -n "$found" ] || { error "no .img in $img"; return 1; }
81
mv "$found" "$out" && rm -Rf "$mtmp"
85
local input="$1" fmt="$2" fout=""
86
inargs "$fmt" "${VALID_FORMATS[@]}" || {
87
error "provided '--format=$fmt' not a valid format:" \
91
[ "$fmt" != "auto" ] && _RET="$fmt" && return 0
92
if [ -d "$input" ]; then
93
debug 1 "${input} is a directory";
97
fout=$(LANG=C file "$input") ||
98
{ error "failed: file $input"; return 1; }
99
case "${fout#$input: }" in
101
fout=$(zcat "$input" | file -)
102
case "${fout#*: }" in
103
POSIX\ tar*) fmt="img-tar";;
104
*) fmt="root-image-gz";;
107
"POSIX tar"*) fmt="img-tar";;
108
*ext[234]\ filesystem*) fmt="root-image";;
109
*[Ss]quashfs*) fmt="squashfs-image";;
111
# if the above failed (on trusty a .tar.gz file was reported
112
# as a Minux file system) then try filename based heuristics
114
*-root.t??|*-root.tar|*-root.tar.??) fmt="root-tar";;
115
*.tar.gz|*.tgz|*.tar) fmt="img-tar";;
116
*.gz) fmt="root-image-gz";;
117
*.squashfs) fmt="squashfs-image";;
119
error "WARN: file '$input' did not match name hueristics"
122
debug 1 "guessing $input is $fmt based on name and 'file' [$fout]";;
124
debug 1 "determined format is $fmt"
129
# given 'input' in format 'fmt' return:
130
# _RET_fmt: the format of _RET_PATH. either
131
# fs-image : a mountable filesystem image.
133
# _RET_path: full path to a file in tempd
134
local input="$1" fmt="$2" tempd="$3" cmd=""
139
get_img_from_tar "$input" "${tempd}/fs-image" "${tempd}"
143
_RET_path="$tempd/fs-image"
144
zcat -c "$input" > "$tempd/fs-image.tmp" &&
145
mv "$tempd/fs-image.tmp" "$tempd/fs-image"
149
_RET_path="$tempd/fs-image"
150
ln -s "$(readlink -f "$input")" "${tempd}/fs-image"
153
_RET_fmt="squashfs-image"
154
_RET_PATH="${tempd}/fs-image"
155
ln -s "$(readlink -f "$input")" "${tempd}/fs-image"
159
_RET_path="${tempd}/fs-dir"
161
cmd=( tar -C "${_RET_path}" -xpSf "$input" \
162
--numeric-owner --xattrs "--xattrs-include=*" )
163
debug 1 "extracting $fmt with ${cmd[*]}"
165
error "failed: extracting $fmt with ${cmd[*]}"
172
_RET_PATH="${tempd}/fs-dir"
173
ln -s "$(readlink -f "$input")" "${tempd}/fs-dir"
176
error "Unknown format '$fmt'";
183
local src_d="$1" out="$2" owner="${3:-$(id -u):$(id -g)}"
184
local tmpfile ret="" cmd=""
185
tmpfile="${out}.${0##*/}.$$" || return
186
cmd=( mksquashfs "$src_d" "$tmpfile" -xattrs -comp xz )
187
ddebug 1 "starting: ${cmd[*]}"
190
ddebug 1 "finished: returned $ret"
191
if [ $ret -eq 0 ]; then
192
chown "$owner" "$tmpfile" ||
193
{ error "failed chown $owner $tmpfile"; return 1; }
194
mv "$tmpfile" "$out" ||
195
{ error "failed to move file to $out"; return 1; }
198
error "mksquashfs failed [$ret]: ${cmd[*]}."
204
local src="$1" out="$2" owner="$3"
206
[ "$(id -u )" = "0" ] && sudo=""
208
cmd=( mount-image-callback "$src" --
209
"$0" dir2squashfs _MOUNTPOINT_ "$out" $owner )
210
debug 1 "calling ${cmd[*]}"
215
local short_opts="hf:O:v"
216
local long_opts="help,format:,owner:,verbose"
218
getopt_out=$(getopt --name "${0##*/}" \
219
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
220
eval set -- "${getopt_out}" ||
221
{ bad_Usage; return; }
223
local cur="" next="" input="" output="" owner="" fmt_in="auto" fmt=""
224
while [ $# -ne 0 ]; do
227
-h|--help) Usage ; exit 0;;
228
-f|--format) fmt_in="$next"; shift;;
229
-O|--owner) owner="$next"; shift;;
230
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
236
[ $# -eq 2 ] || { bad_Usage "must provide input and output."; return; }
240
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
241
{ error "failed to make tempdir"; return 1; }
243
local tempd="${TEMP_D}"
245
determine_format "${src_in}" "${fmt_in}" || return
247
debug 1 "format of '${src_in}' is '$fmt'"
250
dir|squashfs-image|root-tar) :;;
252
[ "$(id -u)" = "0" ] || {
253
error "Cannot convert $fmt to squashfs as non-root";
257
get_usable_input "${src_in}" "$fmt" "$tempd" || return
258
local cfmt="${_RET_fmt}" tpath="${_RET_path}"
260
debug 1 "got format '$cfmt' at temp path '$tpath'"
261
if [ "$cfmt" = "squashfs-image" ]; then
262
local tmpf="$output.$$"
263
cp "$src_in" "$tmpf" &&
264
{ [ -z "$owner" ] || chown "$owner" "$tmpf" ; } &&
265
mv "$tmpf" "$output" || {
267
error "failed copying $src_in to $output"
270
elif [ -f "$tpath" ]; then
271
fsimage2squashfs "$tpath" "$output" "$owner" || return
272
elif [ -d "$tpath" ]; then
273
dir2squashfs "$tpath" "$output" || return
275
error "failed. path='$tpath' cfmt=${cfmt}"
278
error "output in $output. took ${SECONDS}s."
282
if [ "$1" = "dir2squashfs" ]; then