mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-11-02 11:18:18 +00:00
python3 is starting to become the default on all major distributions. Using `/usr/bin/python2` should be safe for the near future.
252 lines
6.2 KiB
Python
Executable File
252 lines
6.2 KiB
Python
Executable File
#!/usr/bin/python2
|
|
|
|
"""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('--inplace',
|
|
action='store_true',
|
|
help="Perform fixups in-place")
|
|
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:]
|
|
|
|
def _spliceMaybe(tag, val):
|
|
val = "${%s-\"%s\"}" % (tag, val,)
|
|
_splice(tag, val)
|
|
|
|
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:
|
|
_spliceMaybe('SFX_UNZIP', '1')
|
|
else:
|
|
_spliceMaybe('SFX_UNZIP', '')
|
|
if opts.unzip_pipe:
|
|
_spliceMaybe('SFX_PIPE', '1')
|
|
else:
|
|
_spliceMaybe('SFX_PIPE', '')
|
|
if opts.unzip_loop:
|
|
_spliceMaybe('SFX_LOOP', '1')
|
|
else:
|
|
_spliceMaybe('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)
|
|
if opts.inplace:
|
|
_spliceMaybe('SFX_INPLACE', '1')
|
|
else:
|
|
_spliceMaybe('SFX_INPLACE', '')
|
|
|
|
# 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)
|