Commit f1f18a44 authored by Kevin Locke's avatar Kevin Locke Committed by Ben Hutchings

Create unmkinitramfs command

This command supports extracting files from an initramfs image.  It is
designed to be a drop-in for cpio wherever an initramfs may be present.

It is implemented using the code from lsinitramfs, which now delegates
to uninitramfs instead of cpio.
Signed-off-by: default avatarKevin Locke <kevin@kevinlocke.name>
[bwh: Rename it from uninitramfs to unmkinitramfs; add to .install list]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent c48108dc
lsinitramfs usr/bin
unmkinitramfs usr/bin
init usr/share/initramfs-tools
scripts usr/share/initramfs-tools
conf/initramfs.conf etc/initramfs-tools
......
......@@ -12,7 +12,7 @@ if [ "$#" -eq 0 ] ; then
exit 1
fi
cpio_args="--extract --quiet --list"
cpio_args="--quiet --list"
OPTIONS=`getopt -o hl --long help,long -n "$0" -- "$@"`
# Check for non-GNU getopt
......@@ -40,73 +40,6 @@ while true; do
esac
done
listarchive()
{
archive="$1"
if zcat -t "${archive}" >/dev/null 2>&1 ; then
zcat "${archive}" | cpio ${cpio_args}
elif xzcat -t "${archive}" >/dev/null 2>&1 ; then
xzcat "${archive}" | cpio ${cpio_args}
elif bzip2 -t "${archive}" >/dev/null 2>&1 ; then
bzip2 -c -d "${archive}" | cpio ${cpio_args}
elif lzop -t "${archive}" >/dev/null 2>&1 ; then
lzop -c -d "${archive}" | cpio ${cpio_args}
fi
}
# Read bytes out of a file, checking that they are valid hex digits
readhex()
{
dd < "$1" bs=1 skip="$2" count="$3" 2> /dev/null | \
LANG=C grep -E "^[0-9A-Fa-f]{$3}\$"
}
# Check for a zero byte in a file
checkzero()
{
dd < "$1" bs=1 skip="$2" count=1 2> /dev/null | \
LANG=C grep -q -z '^$'
}
for initramfs in "$@" ; do
if ! [ -r "${initramfs}" ] ; then
echo "Specified file could not be read." >&2
exit 1
else
echo "${initramfs}"
# There may be a prepended uncompressed archive. cpio
# won't tell us the true size of this so we have to
# parse the headers and padding ourselves. This is
# very roughly based on linux/lib/earlycpio.c
offset=0
while true; do
if checkzero "$initramfs" $offset; then
offset=$((offset + 4))
continue
fi
magic="$(readhex "$initramfs" $offset 6)" || break
test $magic = 070701 || test $magic = 070702 || break
namesize=0x$(readhex "$initramfs" $((offset + 94)) 8)
filesize=0x$(readhex "$initramfs" $((offset + 54)) 8)
offset=$(((offset + 110)))
offset=$(((offset + $namesize + 3) & ~3))
offset=$(((offset + $filesize + 3) & ~3))
done
if [ $offset -ne 0 ]; then
# List uncompressed archive
cpio ${cpio_args} < "$initramfs"
# List main archive
subarchive=$(mktemp ${TMPDIR:-/var/tmp}/lsinitramfs_XXXXXX)
trap "rm -f $subarchive" EXIT
dd < "$initramfs" bs="$offset" skip=1 2> /dev/null \
> $subarchive
listarchive $subarchive
else
listarchive "${initramfs}"
fi
fi
unmkinitramfs $cpio_args < "$initramfs"
done
......@@ -50,4 +50,5 @@ and numerous others.
.BR
.IR initramfs-tools (8),
.IR mkinitramfs (8),
.IR unmkinitramfs (8),
.IR update-initramfs (8).
......@@ -155,4 +155,5 @@ Jeff Bailey <jbailey@raspberryginger.com> and numerous others.
.IR initramfs.conf (5),
.IR initramfs-tools (8),
.IR update-initramfs (8),
.IR lsinitramfs (8).
.IR lsinitramfs (8),
.IR unmkinitramfs (8).
#!/bin/sh
set -eu
usage()
{
echo "Usage: $(basename "$0") [cpio options ...] < <initramfs file>"
}
# Abort if stdin is a terminal.
#
# Although cpio supports this, the chance of someone actually keying in a cpio
# archive on the terminal is negligible compared to the risk of someone who
# forgot cpio's arcane argument convention.
if [ -t 0 ] ; then
echo "Error: stdin must be an initramfs" >&2
usage >&2
exit 1
fi
# Extract a compressed cpio archive
xcpio()
{
archive="$1" ; shift
if zcat -t "$archive" >/dev/null 2>&1 ; then
zcat "$archive" | cpio "$@"
elif xzcat -t "$archive" >/dev/null 2>&1 ; then
xzcat "$archive" | cpio "$@"
elif bzip2 -t "$archive" >/dev/null 2>&1 ; then
bzip2 -c -d "$archive" | cpio "$@"
elif lzop -t "$archive" >/dev/null 2>&1 ; then
lzop -c -d "$archive" | cpio "$@"
# Ignoring other data, which may be garbage at the end of the file
fi
}
# Read bytes out of a file, checking that they are valid hex digits
readhex()
{
dd < "$1" bs=1 skip="$2" count="$3" 2> /dev/null | \
LANG=C grep -E "^[0-9A-Fa-f]{$3}\$"
}
# Check for a zero byte in a file
checkzero()
{
dd < "$1" bs=1 skip="$2" count=1 2> /dev/null | \
LANG=C grep -q -z '^$'
}
# Split an initramfs into archives and call xcpio on each
splitinitramfs()
{
initramfs="$1" ; shift
# There may be a prepended uncompressed archive. cpio
# won't tell us the true size of this so we have to
# parse the headers and padding ourselves. This is
# very roughly based on linux/lib/earlycpio.c
offset=0
while true; do
if checkzero "$initramfs" $offset; then
offset=$((offset + 4))
continue
fi
magic="$(readhex "$initramfs" $offset 6)" || break
test $magic = 070701 || test $magic = 070702 || break
namesize=0x$(readhex "$initramfs" $((offset + 94)) 8)
filesize=0x$(readhex "$initramfs" $((offset + 54)) 8)
offset=$(((offset + 110)))
offset=$(((offset + $namesize + 3) & ~3))
offset=$(((offset + $filesize + 3) & ~3))
done
if [ $offset -ne 0 ]; then
# uncompressed archive
cpio -i "$@" < "$initramfs"
# main archive
subarchive=$(mktemp ${TMPDIR:-/var/tmp}/unmkinitramfs_XXXXXX)
trap "rm -f '$subarchive'" EXIT
dd < "$initramfs" bs="$offset" skip=1 2> /dev/null \
> $subarchive
xcpio "$subarchive" -i "$@"
else
xcpio "$initramfs" -i "$@"
fi
}
# If we can get the name of the file passed in, use it. Otherwise, create one.
stdin_filename=$(readlink /proc/$$/fd/0 2>/dev/null || true)
if ! [ -r "$stdin_filename" ] ; then
stdin_filename=$(mktemp ${TMPDIR:-/var/tmp}/uninitramfs_stdin_XXXXXX)
trap "rm -f '$stdin_filename'" EXIT
cat > "$stdin_filename"
fi
splitinitramfs "$stdin_filename" "$@"
.TH UNMKINITRAMFS 8 "2016/02/09" "Linux" "unmkinitramfs manual"
.SH NAME
unmkinitramfs \- extract content from an initramfs image
.SH SYNOPSIS
.B unmkinitramfs
.RI "" "[cpio options ...]" " < " <initramfsfile>
.br
.SH DESCRIPTION
The
.B unmkinitramfs
command extracts the content of a given initramfs image using
.BR cpio .
If the image contains multiple segments, each are passed to
.B cpio
in order.
.SH OPTIONS
All options are passed through to
.B cpio
, after an initial
.B \-i
option which puts
.B cpio
into \*(lqextract\*(rq or \*(lqCopy-in\*(rq mode.
.SH USAGE EXAMPLES
Extract initramfs content of current running kernel:
.PP
.B unmkinitramfs < /boot/initrd.img-$(uname -r)
Extract
.I init
from the initramfs verbosely and keep its mtime:
.PP
.B unmkinitramfs -m -v init < /boot/initrd.img-$(uname -r)
.SH BUGS
.BR unmkinitramfs
cannot deal with multiple-segmented initramfs images, except where an
early (uncompressed) initramfs with system firmware is prepended to
the regular compressed initramfs.
.SH AUTHOR
The initramfs-tools are written by Maximilian Attems <maks@debian.org>
and numerous others.
.SH SEE ALSO
.BR
.IR initramfs-tools (8),
.IR lsinitramfs (8),
.IR mkinitramfs (8),
.IR update-initramfs (8).
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment