mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-12-25 01:07:01 +00:00
Installer SHAR support.
This commit is contained in:
240
tools/mkshar
Executable file
240
tools/mkshar
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""mkshar
|
||||
|
||||
Generate a shar (with a zip file payload) for a Switch Light installer.
|
||||
"""
|
||||
|
||||
import sys, os, shutil
|
||||
import subprocess
|
||||
import hashlib
|
||||
import optparse
|
||||
|
||||
HELP = """\
|
||||
%prog [OPTIONS] SHAR-OUTPUT SFX-FRAGMENT INSTALL-SCRIPT [ARG ...]
|
||||
"""
|
||||
|
||||
parser = optparse.OptionParser(usage=HELP)
|
||||
parser.add_option('--blocksize',
|
||||
type=int, default=512,
|
||||
help="Set block size for e.g. 'dd'")
|
||||
parser.add_option('--bzip',
|
||||
action='store_true',
|
||||
help="Enable bzip2")
|
||||
parser.add_option('--lazy',
|
||||
action='store_true',
|
||||
help="Enable lazy unpacking")
|
||||
parser.add_option('--unzip-sfx',
|
||||
action='store_true',
|
||||
help="Use 'unzip' to natively handle SFX preamble")
|
||||
parser.add_option('--unzip-pipe',
|
||||
action='store_true',
|
||||
help="Enable 'dd' to handle SFX preamble")
|
||||
parser.add_option('--unzip-loop',
|
||||
action='store_true',
|
||||
help="Enable 'losetup' to handle SFX preamble")
|
||||
parser.add_option('--unzip-pad',
|
||||
action='store_true',
|
||||
help="Special pad options for deficient unzip")
|
||||
parser.add_option('--fixup-perms',
|
||||
type=str,
|
||||
help="Post-unpack shell script to fix permissions")
|
||||
|
||||
opts, args = parser.parse_args()
|
||||
|
||||
ZIP = "/usr/bin/zip"
|
||||
ZIP_OPTS = ['-v',
|
||||
'-y',
|
||||
'-n', '.zip:.loader:.swi:.jar:.gz:.bz:.bz2:.xz',]
|
||||
|
||||
# enable (experimental) bzip2, make sure that
|
||||
# busybox unzip supports it
|
||||
# Ha ha, using '-9' not only cranks up the compression,
|
||||
# but *ignores* the suffix list for 'store-only'.
|
||||
if opts.bzip:
|
||||
ZIP_COMPRESS_OPTS = ['-Z', 'bzip2', '-8',]
|
||||
else:
|
||||
ZIP_COMPRESS_OPTS = ['-8',]
|
||||
|
||||
shar = args.pop(0)
|
||||
sfx = args.pop(0)
|
||||
install = args.pop(0)
|
||||
|
||||
import logging
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger("mkshar")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
logger.info("initializing ZIP")
|
||||
zipFile = os.path.abspath(shar + ".zip.in")
|
||||
if os.path.exists(zipFile):
|
||||
logger.debug("+ /bin/rm %s", zipFile)
|
||||
os.unlink(zipFile)
|
||||
|
||||
def _addfile(path, *opts):
|
||||
logger.info("adding file %s with opts %s",
|
||||
path, " ".join(opts))
|
||||
cmd = [ZIP,] + ZIP_OPTS + list(opts) + ['-u', zipFile, path,]
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
def _addfiles(paths, *opts):
|
||||
logger.info("adding %d files with opts %s",
|
||||
len(paths), " ".join(opts))
|
||||
cmd = [ZIP,] + ZIP_OPTS + list(opts) + [zipFile,] + paths
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
def _zipopts(path):
|
||||
ext = os.path.splitext(path)[1].lower()
|
||||
if ext in ('.loader', '.zip', '.swi',):
|
||||
return ['-0',]
|
||||
else:
|
||||
return ZIP_COMPRESS_OPTS
|
||||
|
||||
# block to 512 bytes
|
||||
buf = open(sfx).read()
|
||||
sz = len(buf)
|
||||
logger.info("script size is %d bytes", sz)
|
||||
rem = sz % opts.blocksize
|
||||
pad = opts.blocksize - rem
|
||||
|
||||
# extra block for house keeping
|
||||
if opts.unzip_pad:
|
||||
pad = pad + opts.blocksize
|
||||
|
||||
if pad == 1:
|
||||
buf += "\n"
|
||||
elif pad > 1:
|
||||
pad -= 1
|
||||
buf = buf + ('#' * pad) + "\n"
|
||||
|
||||
logger.info("padded script size is %d bytes", len(buf))
|
||||
|
||||
if opts.unzip_pad:
|
||||
logger.info("adding SFX pad to beginning as archive item")
|
||||
fd = open("pad.bin", "w")
|
||||
fd.write(('#' * (len(buf)-1)))
|
||||
fd.write('\n')
|
||||
fd.close()
|
||||
_addfile("pad.bin", '-0', '-j')
|
||||
os.unlink("pad.bin")
|
||||
|
||||
_addfile(install, '-0')
|
||||
|
||||
if opts.fixup_perms:
|
||||
_addfile(opts.fixup_perms, '-0')
|
||||
|
||||
logger.info("adding other payload items")
|
||||
o = ['-r',] + ZIP_COMPRESS_OPTS
|
||||
_addfiles(args, *o)
|
||||
|
||||
def _splice(tag, val):
|
||||
global buf
|
||||
pat = tag + '='
|
||||
p = buf.find(pat)
|
||||
q = buf.find("\n", p+1)
|
||||
if p < 0:
|
||||
raise ValueError("cannot find tag %s" % repr(tag))
|
||||
llen = q - p
|
||||
line = "%s=%s #" % (tag, str(val),)
|
||||
if len(line) > llen:
|
||||
raise SystemExit("cannot insert byte count marker")
|
||||
llen -= len(line)
|
||||
line = line + ('#' * llen)
|
||||
buf = buf[:p] + line + buf[q:]
|
||||
|
||||
logger.info("prepping SFX")
|
||||
|
||||
_splice('SFX_BYTES', len(buf))
|
||||
_splice('SFX_BLOCKSIZE', opts.blocksize)
|
||||
_splice('SFX_INSTALL', os.path.split(install)[1])
|
||||
_splice('SFX_CHECKSUM', '')
|
||||
if opts.lazy:
|
||||
_splice('SFX_LAZY', '1')
|
||||
else:
|
||||
_splice('SFX_LAZY', '')
|
||||
if opts.unzip_sfx:
|
||||
_splice('SFX_UNZIP', '1')
|
||||
else:
|
||||
_splice('SFX_UNZIP', '')
|
||||
if opts.unzip_pipe:
|
||||
_splice('SFX_PIPE', '1')
|
||||
else:
|
||||
_splice('SFX_PIPE', '')
|
||||
if opts.unzip_loop:
|
||||
_splice('SFX_LOOP', '1')
|
||||
else:
|
||||
_splice('SFX_LOOP', '')
|
||||
if opts.unzip_pad:
|
||||
_splice('SFX_PAD', 'pad.bin')
|
||||
else:
|
||||
_splice('SFX_PAD', '')
|
||||
if opts.fixup_perms:
|
||||
_splice('SFX_PERMS', opts.fixup_perms)
|
||||
|
||||
# remember the checksum offset
|
||||
ckStart = buf.find("SFX_CHECKSUM=")
|
||||
ckEnd = buf.find("\n", ckStart+1)
|
||||
|
||||
logger.info("generating shar")
|
||||
|
||||
if opts.unzip_pad:
|
||||
|
||||
wfd = open(shar, "w+")
|
||||
rfd = open(zipFile, "r")
|
||||
shutil.copyfileobj(rfd, wfd)
|
||||
rfd.close()
|
||||
|
||||
logger.info("capturing first block")
|
||||
wfd.seek(0, 0)
|
||||
magic = wfd.read(opts.blocksize)
|
||||
|
||||
logger.info("splicing in SFX")
|
||||
wfd.seek(0, 0)
|
||||
wfd.write(buf)
|
||||
|
||||
logger.info("saving first block")
|
||||
wfd.seek(len(buf)-opts.blocksize, 0)
|
||||
wfd.write(magic)
|
||||
|
||||
wfd.close()
|
||||
|
||||
# adjust buf to include magic
|
||||
buf = buf[:-opts.blocksize] + magic
|
||||
|
||||
else:
|
||||
|
||||
wfd = open(shar, "w")
|
||||
wfd.write(buf)
|
||||
rfd = open(zipFile, "r")
|
||||
shutil.copyfileobj(rfd, wfd)
|
||||
rfd.close()
|
||||
wfd.close()
|
||||
|
||||
logger.info("adjusting SFX")
|
||||
cmd = [ZIP,] + ZIP_OPTS + ['-A', shar,]
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
# compute the actual checksum
|
||||
ckf = hashlib.md5()
|
||||
ckf.update(buf[:ckStart])
|
||||
ckf.update(buf[ckEnd+1:])
|
||||
|
||||
rfd = open(shar, "r")
|
||||
rfd.seek(len(buf), 0)
|
||||
while True:
|
||||
buf = rfd.read(10*1024)
|
||||
if not buf: break
|
||||
ckf.update(buf)
|
||||
rfd.close()
|
||||
|
||||
logger.info("adjusting checksum")
|
||||
wfd = open(shar, "r+")
|
||||
wfd.seek(ckStart, 0)
|
||||
wfd.write("SFX_CHECKSUM=%s #" % ckf.hexdigest())
|
||||
wfd.close()
|
||||
|
||||
logger.info("+ /bin/chmod +x %s", shar)
|
||||
os.chmod(shar, 0755)
|
||||
|
||||
logger.debug("+ /bin/rm %s", zipFile)
|
||||
os.unlink(zipFile)
|
||||
283
tools/scripts/sfx.sh.in
Normal file
283
tools/scripts/sfx.sh.in
Normal file
@@ -0,0 +1,283 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
CMD=${0##*/}
|
||||
|
||||
UNZIP=/usr/bin/unzip
|
||||
|
||||
UNZIPOPTS=
|
||||
UNZIPARGS=
|
||||
UNZIPDIR=
|
||||
UNZIPQ="-q"
|
||||
UNZIPV=
|
||||
|
||||
UNZIPLOOP=
|
||||
|
||||
mode=install
|
||||
|
||||
SHAR=$0
|
||||
|
||||
shardir=`dirname $SHAR`
|
||||
shardir=`cd $shardir && pwd`
|
||||
SHARABS="$shardir"/${SHAR##*/}
|
||||
|
||||
SFX_BYTES=0 ## fill in the size (padded) of this SFX header ##################
|
||||
SFX_BLOCKSIZE=1 ## use a larger block size, 'dd bs=1' is sometimes slow ######
|
||||
SFX_CHECKSUM= ## compute checksum over this SFX and the payload ##############
|
||||
SFX_INSTALL=install ## internal script in the payload to run #################
|
||||
SFX_PERMS= ## internal script to correct file permissions ####################
|
||||
SFX_PAD= ## pad file (this payload) to skip during unpack ####################
|
||||
SFX_LAZY= ## set to '1' to defer extraction to SFX_INSTALL ##################
|
||||
SFX_UNZIP=1 ## set to '' if this unzip cannot parse SFX headers #############
|
||||
SFX_LOOP=1 ## set to '' if this unzip cannot read from a loopback/block ####
|
||||
SFX_PIPE=1 ## set to '' if this unzip cannot read from a pipe ##############
|
||||
|
||||
if test "$SFX_PAD"; then
|
||||
UNZIPARGS=$UNZIPARGS${UNZIPARGS:+" "}"-x $SFX_PAD"
|
||||
fi
|
||||
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
-x)
|
||||
# N.B. that busybox unzip has trouble with multiple files
|
||||
mode=unzip
|
||||
shift
|
||||
UNZIPARGS=$UNZIPARGS${UNZIPARGS:+" "}"$1"
|
||||
shift
|
||||
UNZIPARGS=$UNZIPARGS${UNZIPARGS:+" "}"$1"
|
||||
continue
|
||||
;;
|
||||
-d)
|
||||
shift
|
||||
UNZIPDIR=$1
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
-v)
|
||||
UNZIPQ=
|
||||
UNZIPV="$1"
|
||||
shift
|
||||
;;
|
||||
-q)
|
||||
UNZIPQ="$1"
|
||||
UNZIPV=
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
mode=unzip
|
||||
UNZIPOPTS=$UNZIPOPTS${UNZIPOPTS:+" "}"$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
mode=unzip
|
||||
UNZIPARGS=$UNZIPARGS${UNZIPARGS:+" "}"$1"
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if test "$SFX_BLOCKSIZE" -gt 1; then
|
||||
SFX_BLOCKS=$(($SFX_BYTES / $SFX_BLOCKSIZE))
|
||||
SFX_TRAILER=$(($SFX_BYTES % $SFX_BLOCKSIZE))
|
||||
if test $SFX_TRAILER -ne 0; then
|
||||
echo "$CMD: *** SFX is not block-aligned" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "$CMD: *** SFX is blocked, dd may be slow" 1>&2
|
||||
fi
|
||||
|
||||
workdir=`mktemp -t -d sfx-XXXXXX` || exit 1
|
||||
do_cleanup()
|
||||
{
|
||||
if test -b "$UNZIPLOOP"; then
|
||||
losetup -d "$UNZIPLOOP" || :
|
||||
fi
|
||||
cd /
|
||||
/bin/rm -fr $workdir 2>/dev/null
|
||||
}
|
||||
trap "do_cleanup" 0 1
|
||||
|
||||
_t()
|
||||
{
|
||||
local c z
|
||||
c="$1"; shift
|
||||
z="$1"; shift
|
||||
$c | $UNZIP $UNZIPQ $UNZIPV -l "$z" 1>/dev/null 2>&1
|
||||
return $?
|
||||
}
|
||||
|
||||
# be wary of busybox unzip
|
||||
# http://lists.busybox.net/pipermail/busybox/2010-August/073131.html
|
||||
case "$SFX_PAD:$SFX_UNZIP:$SFX_LOOP:$SFX_PIPE" in
|
||||
:1:*:*)
|
||||
echo "$CMD: testing for SFX support"
|
||||
if ! _t ":" "$SHARABS"; then
|
||||
echo "$CMD: *** SFX failed" 1>&2
|
||||
SFX_UNZIP=
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$SFX_PAD:$SFX_UNZIP:$SFX_LOOP:$SFX_PIPE" in
|
||||
::1:*)
|
||||
echo "$CMD: testing for loopback support"
|
||||
UNZIPLOOP=`losetup -f`
|
||||
losetup -r -o $SFX_BYTES "$UNZIPLOOP" "$SHARABS"
|
||||
if ! _t ":" "$UNZIPLOOP"; then
|
||||
echo "$CMD: *** loopback failed" 1>&2
|
||||
SFX_LOOP=
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$SFX_PAD:$SFX_UNZIP:$SFX_LOOP:$SFX_PIPE" in
|
||||
:::1)
|
||||
echo "$CMD: testing for pipe support"
|
||||
if ! _t "dd if=$SHARABS bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS" "-"; then
|
||||
echo "$CMD: *** pipe failed" 1>&2
|
||||
SFX_PIPE=
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$SFX_PAD"; then
|
||||
echo "$CMD: copying file and resetting pad"
|
||||
cp "$SHARABS" $workdir/onie-installer.zip
|
||||
dd if="$SHARABS" of=$workdir/onie-installer.zip bs=512 skip=$(($SFX_BLOCKS-1)) count=1 conv=notrunc
|
||||
_CAT=":"
|
||||
_ZIP="$workdir/onie-installer.zip"
|
||||
elif test "$SFX_UNZIP"; then
|
||||
echo "$CMD: processing SFX with unzip"
|
||||
_CAT=":"
|
||||
_ZIP="$SHARABS"
|
||||
elif test "$SFX_LOOP"; then
|
||||
echo "$CMD: processing SFX with losetup"
|
||||
_CAT=":"
|
||||
_ZIP="$UNZIPLOOP"
|
||||
elif test "$SFX_PIPE"; then
|
||||
echo "$CMD: processing SFX with dd"
|
||||
_CAT="dd if=$SHARABS bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS"
|
||||
_ZIP="-"
|
||||
else
|
||||
echo "$CMD: *** copying file to find zip offset"
|
||||
dd if=$SHARABS of=$workdir/onie-installer.zip bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS
|
||||
_CAT=":"
|
||||
_ZIP="$workdir/onie-installer.zip"
|
||||
fi
|
||||
|
||||
if test "$mode" = "unzip"; then
|
||||
echo "$CMD: processing with zip"
|
||||
|
||||
if test "$UNZIPDIR"; then
|
||||
cd "$UNZIPDIR"
|
||||
fi
|
||||
|
||||
$_CAT | $UNZIP $UNZIPQ $UNZIPV $UNZIPOPTS "$_ZIP" $UNZIPARGS
|
||||
sts=$?
|
||||
test $sts -eq 0 || exit $sts
|
||||
|
||||
if test -f "$SFX_PERMS"; then
|
||||
echo "$CMD: correcting permissions with $SFX_PERMS"
|
||||
chmod +x "$SFX_PERMS"
|
||||
./"$SFX_PERMS"
|
||||
fi
|
||||
|
||||
exit $sts
|
||||
fi
|
||||
|
||||
if test "$mode" != "install"; then
|
||||
echo "$CMD: *** invalid mode: $mode" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test "$UNZIPDIR"; then
|
||||
:
|
||||
else
|
||||
UNZIPDIR=$workdir
|
||||
fi
|
||||
|
||||
banner=`unzip 2>&1` || :
|
||||
case "$banner" in
|
||||
*"-t"*)
|
||||
echo "$CMD: testing shar"
|
||||
$_CAT | $UNZIP $UNZIPQ $UNZIPV $UNZIPOPTS -t "$_ZIP" $UNZIPARGS
|
||||
sts=$?
|
||||
test $sts -eq 0 || exit $sts
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$CMD: computing checksum"
|
||||
{
|
||||
dd if="$SHARABS" bs=$SFX_BLOCKSIZE count=$SFX_BLOCKS 2>/dev/null | sed -e "/^SFX_CHECKSUM=/d";
|
||||
dd if="$SHARABS" bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS 2>/dev/null
|
||||
} | md5sum > "$UNZIPDIR/ck"
|
||||
|
||||
set dummy `cat "$UNZIPDIR/ck"`
|
||||
newck=$2
|
||||
|
||||
rm -f "$UNZIPDIR/ck"
|
||||
|
||||
if test "$SFX_CHECKSUM" = "$newck"; then
|
||||
echo "$CMD: checksum is OK"
|
||||
else
|
||||
echo "$CMD: *** checksum mismatch" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
shardir=`dirname $0`
|
||||
shardir=`cd $shardir && pwd`
|
||||
|
||||
echo "$CMD: extracting shar into $UNZIPDIR"
|
||||
cd $UNZIPDIR
|
||||
|
||||
if test "$SFX_LAZY"; then
|
||||
$_CAT | $UNZIP $UNZIPQ $UNZIPOPTS "$_ZIP" "$SFX_INSTALL"
|
||||
else
|
||||
$_CAT | $UNZIP $UNZIPQ $UNZIPOPTS "$_ZIP" $UNZIPARGS
|
||||
fi
|
||||
|
||||
if test -f "$SFX_PERMS"; then
|
||||
echo "$CMD: correcting permissions with $SFX_PERMS"
|
||||
chmod +x "$SFX_PERMS"
|
||||
./"$SFX_PERMS"
|
||||
fi
|
||||
|
||||
if test -f "$SFX_INSTALL"; then
|
||||
echo "$CMD: invoking installer $SFX_INSTALL"
|
||||
|
||||
tmp_install=`mktemp $UNZIPDIR/install-XXXXXX`
|
||||
mv "$SFX_INSTALL" $tmp_install
|
||||
chmod +x "$tmp_install"
|
||||
|
||||
export SFX_BLOCKSIZE SFX_BLOCKS SFX_PAD SFX_UNZIP SFX_LOOP SFX_PIPE SFX_LAZY SFX_PERMS
|
||||
|
||||
case "$-" in
|
||||
*x*)
|
||||
dashx="-x"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -e "$_ZIP"; then
|
||||
eval "$tmp_install" $dashx "$_ZIP"
|
||||
else
|
||||
eval "$tmp_install" $dashx "$SHARABS"
|
||||
fi
|
||||
|
||||
exit $?
|
||||
else
|
||||
echo "$CMD: *** missing installer: $SFX_INSTALL" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##############################
|
||||
#
|
||||
# END OF SHAR HEADER
|
||||
#
|
||||
# BINARY ZIP DATA FOLLOWS
|
||||
#
|
||||
# DO NOT EDIT!
|
||||
#
|
||||
##############################
|
||||
Reference in New Issue
Block a user