summaryrefslogtreecommitdiffstats
path: root/opkg-unbuild
blob: 27096a1bfbcbfb01fca17ddc5c7de92c90c44a58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/bin/sh -e
# opkg-unbuild PKG... - extract packages to the current directory

# SPDX-License-Identifier: GPL-2.0-only
# Author: Christian Hermann <mail@hermannch.dev>

fail() { printf -- 'FAIL: %s\n' "$1" >&2 ; exit "${2:-1}" ; }
usage() {
	printf '%s\n' "Usage: $(basename "$0") PKG..."
	printf '%s\n' "    Extract debian compatible packages to the current directory"
}

# map file suffix to tar compression flag
get_tar_comp_flag() {
	case "$1" in
		# avoid -a, which has a different meaning in busybox-tar
		*tar.gz|*tgz) printf -- '-z' ;;
		*tar.xz|*txz) printf -- '-J' ;;
		*tar.bz2|*tbz|*tbz2) printf -- '-j' ;;
		*tar.lzma|*tlz) printf -- '--auto-compress' ;;
		*) printf -- '--auto-compress' ;;
	esac
}


if [ "$#" -lt 1 ] ; then
	usage >&2
	exit 1
fi
if [ "$1" = "-h" ] || [ "$1" = "--help" ] ; then
	usage
	exit 0
fi

while [ -n "$1" ] ; do
	filename="$1"
	shift

	[ ! -r "$filename" ] && fail "Cannot read file: $filename"

	# Prepare directory name (strip suffix)
	pkgname="$(basename "$filename")"
	pkgdir="./$(printf '%s' "$pkgname" | sed -E 's/\.((ipk)|(opk)|(deb))//')/"

	# Skip this package if there's a naming clash with the target dir
	if [ -d "$pkgdir" ]; then
		printf '%s\n' "Destination already exists: $pkgdir (skipping)" >&2
		continue
	fi

	# Analyze outer layer, prefer ar over tar
	outer_ext_cmd=
	table=
	if ar t "$filename" >/dev/null 2>&1 ; then
		outer_ext_cmd="ar p "
		table="$(ar t "$filename" 2>/dev/null)"
	elif tar t -f "$filename" >/dev/null 2>&1 ; then
		outer_ext_cmd="tar -x --to-stdout --file "
		table="$(tar -t -f "$filename")"
	fi
	[ -z "$table" ] && fail "Could not read file table: $filename"

	# Analyze inner layer.  Choose decompression algo for inner archives as
	# indicated by their suffix.  Query the real paths from the outer archive's
	# table, since tar's table prefixes them with ./ while ar's does not.
	control_path="$(printf '%s' "$table" | grep control)"
	data_path="$(printf '%s' "$table" | grep data)"
	[ -z "$control_path" ] && fail "Archive has no control.tar.gz: $filename"
	[ -z "$data_path" ] && fail "Archive has no data.tar.gz: $filename"
	inner_comp_control="$(get_tar_comp_flag "$control_path")"
	inner_comp_data="$(get_tar_comp_flag "$data_path")"

	# Extract
	mkdir -p "$pkgdir/CONTROL"
	$outer_ext_cmd "$filename" "$control_path" | tar --extract -f - "$inner_comp_control" -C "$pkgdir/CONTROL"
	$outer_ext_cmd "$filename" "$data_path" | tar --extract -f - "$inner_comp_data" -C "$pkgdir/"

	# Summary
	printf 'Unbuilt %s into %s\n' "$filename" "$pkgdir"
done