diff --git a/pmb/flasher/export.py b/pmb/flasher/export.py index 5a2c9905..18718bf1 100644 --- a/pmb/flasher/export.py +++ b/pmb/flasher/export.py @@ -24,13 +24,20 @@ import pmb.build import pmb.chroot.apk import pmb.config import pmb.flasher +import pmb.helpers.file def export(args, flavor, folder): + logging.info("Export symlinks to: " + folder) + if args.odin_flashable_tar: + odin_flashable_tar(args, flavor, folder) + symlinks(args, flavor, folder) + + +def symlinks(args, flavor, folder): """ Create convenience symlinks to the system image and boot files. """ - logging.info("Export symlinks to: " + folder) # File descriptions info = { @@ -65,13 +72,87 @@ def export(args, flavor, folder): msg += " (" + info[basename] + ")" logging.info(msg) - if os.path.exists(link): - if (os.path.islink(link) and - os.path.abspath(os.readlink(link)) == os.path.abspath(file)): - continue - raise RuntimeError("File exists: " + link) - elif os.path.islink(link): - os.unlink(link) + pmb.helpers.file.symlink(args, file, link) - # Create the symlink - pmb.helpers.run.user(args, ["ln", "-s", file, link]) + +def odin_flashable_tar(args, flavor, folder): + """ + Create Odin flashable tar file with kernel and initramfs for devices configured with + the flasher method 'heimdall-isorec' and with boot.img for devices with 'heimdall-bootimg' + """ + pmb.flasher.init(args) + suffix = "rootfs_" + args.device + + # Validate method + method = args.deviceinfo["flash_methods"] + if not method.startswith("heimdall-"): + raise RuntimeError("An odin flashable tar is not supported for the flash" + " method '" + method + "' specified in the current configuration." + " Only 'heimdall' methods are supported.") + + # Partitions + partition_kernel = args.deviceinfo["flash_heimdall_partition_kernel"] + partition_initfs = args.deviceinfo["flash_heimdall_partition_initfs"] + + # Temporary folder + temp_folder = "/tmp/odin-flashable-tar" + + # Odin flashable tar generation script (because redirecting stdin/stdout is not allowed + # in pmbootstrap's chroot/shell functions for security reasons) + with open(args.work + "/chroot_rootfs_" + args.device + "/tmp/_odin.sh", "w") as handle: + odin_kernel_md5 = partition_kernel + ".bin.md5" + odin_initfs_md5 = partition_initfs + ".bin.md5" + odin_device_tar = args.device + ".tar" + odin_device_tar_md5 = args.device + ".tar.md5" + + handle.write( + "#!/bin/sh\n" + "cd " + temp_folder + "\n") + if method == "heimdall-isorec": + handle.write( + # Kernel: copy and append md5 + "cp /boot/vmlinuz-" + flavor + " " + odin_kernel_md5 + "\n" + "md5sum -t " + odin_kernel_md5 + " >> " + odin_kernel_md5 + "\n" + # Initramfs: recompress with lzop, append md5 + "gunzip -c /boot/initramfs-" + flavor + " | lzop > " + odin_initfs_md5 + "\n" + "md5sum -t " + odin_initfs_md5 + " >> " + odin_initfs_md5 + "\n") + elif method == "heimdall-bootimg": + handle.write( + # boot.img: copy and append md5 + "cp /boot/boot.img-" + flavor + " " + odin_kernel_md5 + "\n" + "md5sum -t " + odin_kernel_md5 + " >> " + odin_kernel_md5 + "\n") + handle.write( + # Create tar, remove included files and append md5 + "tar -c -f " + odin_device_tar + " *.bin.md5\n" + "rm *.bin.md5\n" + "md5sum -t " + odin_device_tar + " >> " + odin_device_tar + "\n" + "mv " + odin_device_tar + " " + odin_device_tar_md5 + "\n") + + commands = [["mkdir", "-p", temp_folder], + ["cat", "/tmp/_odin.sh"], # for the log + ["sh", "/tmp/_odin.sh"], + ["rm", "/tmp/_odin.sh"] + ] + for command in commands: + pmb.chroot.root(args, command, suffix) + + # Move Odin flashable tar to native chroot and cleanup temp folder + pmb.chroot.user(args, ["mkdir", "-p", "/home/user/rootfs"]) + pmb.chroot.root(args, ["mv", "/mnt/rootfs_" + args.device + temp_folder + + "/" + odin_device_tar_md5, "/home/user/rootfs/"]), + pmb.chroot.root(args, ["chown", "user:user", + "/home/user/rootfs/" + odin_device_tar_md5]) + pmb.chroot.root(args, ["rmdir", temp_folder], suffix) + + # Create the symlink + file = args.work + "/chroot_native/home/user/rootfs/" + odin_device_tar_md5 + link = folder + "/" + odin_device_tar_md5 + pmb.helpers.file.symlink(args, file, link) + + # Display a readable message + msg = " * " + odin_device_tar_md5 + if method == "heimdall-isorec": + msg += " (Odin flashable file, contains initramfs and kernel)" + elif method == "heimdall-bootimg": + msg += " (Odin flashable file, contains boot.img)" + logging.info(msg) diff --git a/pmb/flasher/frontend.py b/pmb/flasher/frontend.py index f50e623c..9256f7ef 100644 --- a/pmb/flasher/frontend.py +++ b/pmb/flasher/frontend.py @@ -56,7 +56,6 @@ def kernel(args): pmb.chroot.initfs.build(args, flavor, "rootfs_" + args.device) # Generate the paths and run the flasher - pmb.flasher.init(args) if args.action_flasher == "boot": logging.info("(native) boot " + flavor + " kernel") pmb.flasher.run(args, "boot", flavor) @@ -86,7 +85,6 @@ def system(args): if not os.path.exists(args.work + "/chroot_native" + img_path): raise RuntimeError("The system image has not been generated yet," " please run 'pmbootstrap install' first.") - pmb.flasher.init(args) # Run the flasher logging.info("(native) flash system image") diff --git a/pmb/helpers/file.py b/pmb/helpers/file.py index a35bc20e..3efe5463 100644 --- a/pmb/helpers/file.py +++ b/pmb/helpers/file.py @@ -19,6 +19,8 @@ along with pmbootstrap. If not, see . import os +import pmb.helpers.run + def replace(path, old, new): text = "" @@ -56,3 +58,19 @@ def is_up_to_date(path_sources, path_target=None, lastmod_target=None): lastmod_target = os.path.getmtime(path_target) return lastmod_target >= lastmod_source + + +def symlink(args, file, link): + """ + Checks if the symlink is already present, otherwise create it. + """ + if os.path.exists(link): + if (os.path.islink(link) and + os.path.abspath(os.readlink(link)) == os.path.abspath(file)): + return + raise RuntimeError("File exists: " + link) + elif os.path.islink(link): + os.unlink(link) + + # Create the symlink + pmb.helpers.run.user(args, ["ln", "-s", file, link]) diff --git a/pmb/parse/arguments.py b/pmb/parse/arguments.py index 81b9bcee..165c1ced 100644 --- a/pmb/parse/arguments.py +++ b/pmb/parse/arguments.py @@ -46,6 +46,8 @@ def arguments_flasher(subparser): export.add_argument("export_folder", help="export folder, defaults to" " /tmp/postmarketOS-export", default="/tmp/postmarketOS-export", nargs="?") + export.add_argument("--odin", help="odin flashable tar (boot.img/kernel+initramfs only)", + action="store_true", dest="odin_flashable_tar") return ret