├── .gitignore ├── CONTRIBUTIONS.md ├── CREDITS.md ├── LICENSE-GPLv3.txt ├── README.md ├── docs ├── bootdisk_create.md ├── make_bootable.md ├── multiboot_create.md ├── multiboot_install_grub.md ├── multiboot_update_config.md ├── tree.txt └── ubuntu_remaster_iso.md ├── notes ├── distrolinks.txt ├── distronotes.txt ├── efi_general.txt ├── efibootmgr.txt ├── grubinstall.txt └── secure_boot.txt ├── remaster ├── chroot │ ├── commands │ │ ├── 02_install_kernels.sh │ │ ├── 03_remove_old_kernels.sh │ │ ├── 05_update_all_packages.sh │ │ ├── 06_install_grub_packages.sh │ │ ├── 07_apt_cleanup.sh │ │ └── 08_copy_scripts.sh │ └── scripts │ │ ├── __boot_grub_mkconfig.sh │ │ ├── __chroot_grub_mkconfig.sh │ │ ├── __remaster_toplevel.sh │ │ ├── bootdisk_create.py │ │ ├── common_utils.py │ │ ├── efiutils.py │ │ ├── erase_initialize_disk.py │ │ ├── grub_embedded.cfg │ │ ├── install_grub_pkgs.sh │ │ ├── isoparser │ │ ├── __init__.py │ │ ├── iso.py │ │ ├── path_table.py │ │ ├── record.py │ │ ├── rockridge.py │ │ ├── source.py │ │ ├── susp.py │ │ └── volume_descriptors.py │ │ ├── linuxiso.py │ │ ├── make_bootable.py │ │ ├── multiboot.py │ │ ├── multiboot_create.py │ │ ├── multiboot_install_grub.py │ │ ├── multiboot_update_config.py │ │ ├── pkgs_missing_from.sh │ │ ├── remaster_iso_functions.sh │ │ ├── required_pkgs.sh │ │ ├── show_disks.py │ │ ├── show_iso_details.py │ │ └── ubuntu_remaster_iso.sh └── iso_post │ ├── commands │ ├── 01_update_iso_kernel.sh │ └── 02_update_efi.sh │ └── efi │ ├── EFI │ └── BOOT │ │ ├── BOOTx64.EFI │ │ ├── bootia32.efi │ │ └── grubx64.efi │ └── boot │ └── grub │ ├── efi.img │ ├── font.pf2 │ ├── grub.cfg │ ├── loopback.cfg │ └── x86_64-efi │ ├── acpi.mod │ ├── adler32.mod │ ├── ahci.mod │ ├── all_video.mod │ ├── aout.mod │ ├── appleldr.mod │ ├── archelp.mod │ ├── at_keyboard.mod │ ├── ata.mod │ ├── backtrace.mod │ ├── bfs.mod │ ├── bitmap.mod │ ├── bitmap_scale.mod │ ├── blocklist.mod │ ├── boot.mod │ ├── bsd.mod │ ├── btrfs.mod │ ├── bufio.mod │ ├── cat.mod │ ├── cbfs.mod │ ├── cbls.mod │ ├── cbmemc.mod │ ├── cbtable.mod │ ├── cbtime.mod │ ├── chain.mod │ ├── cmdline_cat_test.mod │ ├── cmp.mod │ ├── command.lst │ ├── cpio.mod │ ├── cpio_be.mod │ ├── cpuid.mod │ ├── crc64.mod │ ├── crypto.lst │ ├── crypto.mod │ ├── cryptodisk.mod │ ├── cs5536.mod │ ├── date.mod │ ├── datehook.mod │ ├── datetime.mod │ ├── disk.mod │ ├── diskfilter.mod │ ├── div_test.mod │ ├── dm_nv.mod │ ├── echo.mod │ ├── efi_gop.mod │ ├── efi_uga.mod │ ├── efifwsetup.mod │ ├── efinet.mod │ ├── ehci.mod │ ├── elf.mod │ ├── eval.mod │ ├── exfat.mod │ ├── exfctest.mod │ ├── ext2.mod │ ├── fat.mod │ ├── file.mod │ ├── fixvideo.mod │ ├── font.mod │ ├── fs.lst │ ├── gcry_arcfour.mod │ ├── gcry_blowfish.mod │ ├── gcry_camellia.mod │ ├── gcry_cast5.mod │ ├── gcry_crc.mod │ ├── gcry_des.mod │ ├── gcry_dsa.mod │ ├── gcry_idea.mod │ ├── gcry_md4.mod │ ├── gcry_md5.mod │ ├── gcry_rfc2268.mod │ ├── gcry_rijndael.mod │ ├── gcry_rmd160.mod │ ├── gcry_rsa.mod │ ├── gcry_seed.mod │ ├── gcry_serpent.mod │ ├── gcry_sha1.mod │ ├── gcry_sha256.mod │ ├── gcry_sha512.mod │ ├── gcry_tiger.mod │ ├── gcry_twofish.mod │ ├── gcry_whirlpool.mod │ ├── geli.mod │ ├── gettext.mod │ ├── gfxmenu.mod │ ├── gfxterm.mod │ ├── gfxterm_background.mod │ ├── gfxterm_menu.mod │ ├── gptsync.mod │ ├── grub.cfg │ ├── gzio.mod │ ├── halt.mod │ ├── hashsum.mod │ ├── hdparm.mod │ ├── help.mod │ ├── hexdump.mod │ ├── hfs.mod │ ├── hfsplus.mod │ ├── hfspluscomp.mod │ ├── http.mod │ ├── iorw.mod │ ├── jfs.mod │ ├── jpeg.mod │ ├── keylayouts.mod │ ├── keystatus.mod │ ├── ldm.mod │ ├── legacy_password_test.mod │ ├── legacycfg.mod │ ├── linux.mod │ ├── linux16.mod │ ├── linuxefi.mod │ ├── loadbios.mod │ ├── loadenv.mod │ ├── loopback.mod │ ├── ls.mod │ ├── lsacpi.mod │ ├── lsefi.mod │ ├── lsefimmap.mod │ ├── lsefisystab.mod │ ├── lsmmap.mod │ ├── lspci.mod │ ├── lssal.mod │ ├── luks.mod │ ├── lvm.mod │ ├── lzopio.mod │ ├── macbless.mod │ ├── macho.mod │ ├── mdraid09.mod │ ├── mdraid09_be.mod │ ├── mdraid1x.mod │ ├── memrw.mod │ ├── minicmd.mod │ ├── minix2.mod │ ├── minix2_be.mod │ ├── minix3.mod │ ├── minix3_be.mod │ ├── minix_be.mod │ ├── mmap.mod │ ├── moddep.lst │ ├── morse.mod │ ├── mpi.mod │ ├── msdospart.mod │ ├── multiboot.mod │ ├── multiboot2.mod │ ├── nativedisk.mod │ ├── net.mod │ ├── newc.mod │ ├── ntfs.mod │ ├── ntfscomp.mod │ ├── odc.mod │ ├── offsetio.mod │ ├── ohci.mod │ ├── part_acorn.mod │ ├── part_amiga.mod │ ├── part_apple.mod │ ├── part_bsd.mod │ ├── part_dfly.mod │ ├── part_dvh.mod │ ├── part_gpt.mod │ ├── part_msdos.mod │ ├── part_plan.mod │ ├── part_sun.mod │ ├── part_sunpc.mod │ ├── partmap.lst │ ├── parttool.lst │ ├── parttool.mod │ ├── password.mod │ ├── password_pbkdf2.mod │ ├── pata.mod │ ├── pbkdf2.mod │ ├── pbkdf2_test.mod │ ├── pcidump.mod │ ├── play.mod │ ├── png.mod │ ├── priority_queue.mod │ ├── probe.mod │ ├── procfs.mod │ ├── progress.mod │ ├── raid5rec.mod │ ├── raid6rec.mod │ ├── read.mod │ ├── reboot.mod │ ├── regexp.mod │ ├── reiserfs.mod │ ├── relocator.mod │ ├── romfs.mod │ ├── scsi.mod │ ├── serial.mod │ ├── setjmp.mod │ ├── setjmp_test.mod │ ├── setpci.mod │ ├── signature_test.mod │ ├── sleep.mod │ ├── sleep_test.mod │ ├── spkmodem.mod │ ├── squash4.mod │ ├── syslinuxcfg.mod │ ├── terminal.lst │ ├── terminal.mod │ ├── terminfo.mod │ ├── test.mod │ ├── test_blockarg.mod │ ├── testload.mod │ ├── testspeed.mod │ ├── tftp.mod │ ├── tga.mod │ ├── time.mod │ ├── tr.mod │ ├── trig.mod │ ├── true.mod │ ├── udf.mod │ ├── ufs1.mod │ ├── ufs1_be.mod │ ├── ufs2.mod │ ├── uhci.mod │ ├── usb.mod │ ├── usb_keyboard.mod │ ├── usbms.mod │ ├── usbserial_common.mod │ ├── usbserial_ftdi.mod │ ├── usbserial_pl2303.mod │ ├── usbserial_usbdebug.mod │ ├── usbtest.mod │ ├── verify.mod │ ├── video.lst │ ├── video.mod │ ├── video_bochs.mod │ ├── video_cirrus.mod │ ├── video_colors.mod │ ├── video_fb.mod │ ├── videoinfo.mod │ ├── videotest.mod │ ├── videotest_checksum.mod │ ├── xfs.mod │ ├── xnu.mod │ ├── xnu_uuid.mod │ ├── xnu_uuid_test.mod │ ├── xzio.mod │ └── zfscrypt.mod └── scripts ├── __boot_grub_mkconfig.sh ├── __chroot_grub_mkconfig.sh ├── __remaster_toplevel.sh ├── bootdisk_create.py ├── common_utils.py ├── create_efi.sh ├── disk_partition_functions.sh ├── efi_functions.sh ├── efiutils.py ├── erase_initialize_disk.py ├── grub_embedded.cfg ├── install_grub_pkgs.sh ├── isoparser ├── __init__.py ├── iso.py ├── path_table.py ├── record.py ├── rockridge.py ├── source.py ├── susp.py └── volume_descriptors.py ├── linuxiso.py ├── make_bootable.py ├── missing_firmware.sh ├── multiboot.py ├── multiboot_create.py ├── multiboot_install_grub.py ├── multiboot_update_config.py ├── pkgs_missing_from.sh ├── remaster_iso_functions.sh ├── required_pkgs.sh ├── show_1_disk.py ├── show_disks.py ├── show_disks_lsblk ├── show_iso_details.py ├── show_partitions_lsblk ├── six.py ├── ubuntu_remaster_iso.sh └── updated_firmware.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /CONTRIBUTIONS.md: -------------------------------------------------------------------------------- 1 | 2 | Ideas, suggestions, bug reports and pull requests are all welcome. 3 | 4 | Ideas, suggestions: Raise an issue on github _OR_ email me at sun.nagarajan@gmail.com 5 | 6 | Bug reports: Please raise an issue on github 7 | 8 | Pull requests: Please submit on github 9 | -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | 2 | scripts/isoparser is from [isoparser](https://github.com/barneygale/isoparser) and used unmodified. 3 | 4 | 5 | ```remaster/chroot/r8723bs-bluetooth/hardware/bluetooth/src/rtl8723bs_bt``` 6 | and ```remaster/chroot/r8723bs-bluetooth/hardware/bluetooth/rtl8723bs_bt``` 7 | are from [rtl8723bs_bt by Larry Finger](https://github.com/lwfinger/rtl8723bs_bt) and used unmodified. 8 | 9 | 10 | ```scripts/remaster_iso_functions.sh``` was originally inspired by [linuxium-install-xenial-lts-kernel-4.10.0-10.12-16.04.2-linuxium.sh](https://linuxiumcomau.blogspot.com.au/2017/03/ubuntu-16042-and-ubuntu-1704-beta-1.ht) by [linuxium (Ian Morrison)](https://www.blogger.com/profile/16579769072594848618). However ```scripts/remaster_iso_functions.sh``` has now been completely rewritten from scratch. Ian Morrison has extended and improved his isorespin utility and the latest version can be found [on github here](https://github.com/linuxium/UbuntuLiveUSB). 11 | 12 | Files under ```remaster/iso_post/efi``` are from [linuxium's UbuntuLiveUSB](https://github.com/linuxium/UbuntuLiveUSB) 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bootutils 2 | Utilities to create bootable disks, remaster ISO images, make multiboot disk images 3 | 4 | ## Goals - who needs this? 5 | ### Use case 1: Multiboot disk image 6 | - You want to put one or more ISO images on a single disk and be able to choose which ISO to boot 7 | - You want to be able to boot on UEFI as well as non-UEFI systems 8 | - You want to boot on newer Cherry Trail or Bay Trail (Intel Atom) machines that often have a 32-bit EFI loader, while typical Linux ISO images only support UEFI in 64-bit images 9 | - You want to boot a 64-bit Linux ISO on machines having only a 32-bit EFI loader 10 | - You do not want to have to edit grub.cfg by hand after adding ISO images 11 | 12 | ### Use case 2: Remastering ISO 13 | - You want to add a custom kernel to an ISO to enable support for newer hardware while in the live session 14 | - You want the custom kernel to be automatically installed while installing from the live ISO 15 | - You want to install additional packages that are available in the live session **AND** carried into the installed image 16 | - You want to add additional files - e.g. utilities, scripts, data files - that are available in the live session **AND** carried into the installed image 17 | - You want to make a UEFI-compatible 64-bit Linux ISO image bootable on a machine with a 32-bit EFI loader 18 | - You want to create an updated ISO with all packages updated 19 | 20 | ### Use case 3: Create boot disk on separate disk 21 | - You have a disk that is seen and usable under Linux, but is not seen by the BIOS / UEFI - e.g. newer PCI-Express NVME M.2 disks 22 | - You need a boot image that can contain ONLY /boot, which will then boot from the other disk that the BIOS / UEFI cannot see 23 | 24 | ### Use case 4: Fix grub-install errors 25 | - Linux installer fails after grub-install step - usually bug in installer 26 | - You want to recover and continue 27 | 28 | 29 | ## Operating system support 30 | Linux-only. No effort spent on supporting other OS 31 | 32 | ## Linux distributions supported 33 | The scripts should work on any *modern* Linux distribution. I test on Ubuntu Xenial 16.04.2 LTS. The list of packages required are specific to Ubuntu (Xenial), but the dependency is based on OS commands requried and the OS commands required are listed below, to allow usage on virtually any Linux distribution. 34 | 35 | ### Remastering ISOs 36 | Remastering ISOs is *currently* supported **ONLY for Ubuntu ISOs**. This includes: 37 | 38 | - Ubuntu (*standard* Unity) 39 | - Official Ubuntu flavors such as Ubuntu Mate, xubuntu lubuntu, kubuntu, edubuntu etc) 40 | - Ubuntu derivatives such as Linux Mint (only Linux Mint tested) 41 | 42 | In the future, I intend to support major distributions, such as Fedora, Arch, GRML, Red Hat etc. 43 | 44 | The sample remastering scripts included are Ubuntu-specific. 45 | 46 | ### Multiboot 47 | Multiboot refers to creating a bootable disk that can contain multiple bootable ISO images, supporting a boot-time menu to choose the ISO that you want to boot. 48 | 49 | Once a multiboot image is created, you can add ISO images by copying ISO files to *ISO* directory on the disk and run ```multiboot_update_config.py``` to automatically update the menu (```grub.cfg```). 50 | 51 | Multiboot disk images support: 52 | - Booting on UEFI and non-UEFI host systems 53 | - Booting on UEFI host systems with 32-bit or 64-bit EFI loaders 54 | - Boot 64-bit ISO on a UEFI host system with native 64-bit support even if EFI loader is 32-bit 55 | - Boot 32-bit ISO on a UEFI host system with native 64-bit support even if EFI loader is 64-bit 56 | 57 | Multiboot supports the following distributions within as ISOs: 58 | 59 | - Ubuntu - all official flavors 60 | - Linux Mint 61 | - GRML 62 | - Debian 63 | 64 | In the future, I intend to support major distributions, such as Fedora, Arch, GRML, Red Hat etc. 65 | 66 | Multiboot does **NOT** support ISOs that are not **live CD images** (such as Ubuntu server install ISOs) and probably never will. 67 | 68 | ## Commands and packages required 69 | 70 | | Command | Ubuntu Package | Ubuntu package version tested | 71 | | ------- | -------------- | ----------------------------- | 72 | | lsblk | util-linux | 2.27.1-6ubuntu3.2 | 73 | | parted | parted | 3.2-15 | 74 | | sgdisk | gdisk | 1.0.1-1build1 | 75 | | blkid | util-linux | 2.27.1-6ubuntu3.2 | 76 | | umount | mount | 2.27.1-6ubuntu3.2 | 77 | | mkfs.vfat | dosfstools | 3.0.28-2ubuntu0.1 | 78 | | grub-install | grub2-common | 2.02~beta2-36ubuntu3.9 | 79 | | grub-mkdevicemap | grub-common | 2.02~beta2-36ubuntu3.9 | 80 | | grub-mkconfig | grub-common | 2.02~beta2-36ubuntu3.9 | 81 | | grub-mkstandalone | grub-common | 2.02~beta2-36ubuntu3.9 | 82 | 83 | On Ubuntu (or other Debian-derived distributions, probably), you can run ```required_pkgs.sh``` to find the exact missing packages you need to install. 84 | 85 | ## Help on individual utilities 86 | 87 | [multiboot_create.py](docs/multiboot_create.md) 88 | 89 | [multiboot_install_grub.py](docs/multiboot_install_grub.md) 90 | 91 | [multiboot_update_config.py](docs/multiboot_update_config.md) 92 | 93 | [bootdisk_create.py](docs/bootdisk_create.md) 94 | 95 | [make_bootable.py](docs/make_bootable.md) 96 | -------------------------------------------------------------------------------- /docs/bootdisk_create.md: -------------------------------------------------------------------------------- 1 | # bootdisk_create.py 2 | 3 | This script creates a UEFI-only bootable disk that contains ONLY EFI partition and /boot partition. It also has a built-in reference to UUID of the root filesystem. It is useful in situations like: 4 | - You have a disk that is seen and is usable in Linux, but an older UEFI firmware cannot see the disk and boot from it. An example I have is a PCI-Express NVME M.2 disk that cannot be seen by my UEFI firmware. 5 | 6 | This method puts a file named ```grub_fs_uuid.cfg``` in the root dir of the EFI partition. The embedded grub config looks for and reads this file to locate the root disk and locate grub.cfg. 7 | 8 | If the root partition is recreated - e.g. from a backup - only ```grub_fs_uuid.cfg``` needs to be updated with the new UUID. 9 | 10 | If the additional steps listed at the bottom are performed, ```update-grub``` will update ```boot/grub.cfg``` through the ```/boot``` symlink 11 | 12 | This program must be run as root. 13 | 14 | ``` 15 | Usage: bootdisk_create.py dev_path boot_dir 16 | 17 | dev_path: path to disk (e.g. /dev/sdh} 18 | boot_dir: path to copy boot files from 19 | 20 | Following are available disks 21 | Disk path RM Model-Serial-Rev 22 | /dev/nvme0n1 N Samsung_SSD_960_EVO_250GB S3ESNX0HB04042L 1B7QCXE7 23 | /dev/sda N Hitachi_HDS72105 A3EA 24 | /dev/sdp Y Store_n_Go_Drive 1100 25 | /dev/sds Y Voyager 1100 26 | ``` 27 | 28 | Upon choosing a disk, you will see output like the following: 29 | 30 | ``` 31 | # ./bootdisk_create.py /dev/sds 32 | Scanning partitions on /dev/sds 33 | Confirm disk to update grub. Data will not be affected /dev/sds 34 | 35 | 36 | Model: Corsair Voyager (scsi) 37 | Disk /dev/sds: 8020MB 38 | Sector size (logical/physical): 512B/512B 39 | Partition Table: gpt 40 | Disk Flags:Disk /dev/sds: 15663104 sectors, 7.5 GiB 41 | Logical sector size: 512 bytes 42 | Disk identifier (GUID): 8943D01D-3963-460C-8B69-D52642E3BEAB 43 | Partition table holds up to 128 entries 44 | First usable sector is 34, last usable sector is 15663070 45 | Partitions will be aligned on 2048-sector boundaries 46 | Total free space is 2014 sectors (1007.0 KiB) 47 | Removable: True 48 | Disk Model-Rev: Voyager 1100 49 | 50 | Num Start End Size Code Name FS Path 51 | 1 2048 43007 21.0MB EF02 BIOSGRUB /dev/sds1 52 | 2 43008 15663070 7997MB EF00 EFI vfat /dev/sds2 53 | 54 | Enter "YES" to confirm: 55 | YES 56 | ``` 57 | 58 | ## Additional steps required after creating boot disk 59 | Customize as requried 60 | 61 | ```bash 62 | cd / 63 | mkdir -p /mnt/boot 64 | ln -s /mnt/boot/boot /boot 65 | ``` 66 | 67 | Add line to ```/etc/fstab``` to mount ```/boot``` and ```/boot/efi```from boot disk created: 68 | ``` 69 | UUID=86b56faf-910c-4e56-9eb0-883774bc2a09 /mnt/boot ext4 errors=remount-ro 0 2 70 | UUID=2398-BBB5 /mnt/boot/boot/efi vfat umask=0077 0 2 71 | ``` 72 | -------------------------------------------------------------------------------- /docs/make_bootable.md: -------------------------------------------------------------------------------- 1 | # make_bootable.py 2 | 3 | Sometimes your grub-install fails and you're left without a boot disk that will work. Sometimes this happens at the end of a Linux install. 4 | 5 | This script takes two pieces of information and makes your boot disk bootable - on UEFI or non-UEFI systems 6 | 7 | ## Pre-requisites 8 | - You must have created the disk image originally using ```erase_initialize_disk.py``` 9 | - What is important is it should have: 10 | - A GPT partition table (not MBR) 11 | - A 'BIOS' partition (GPT partition code EF02). If such a partition is not present, grub-mbr will not be used, and the disk will not boot on non-UEFI systems 12 | - An EFI partition (GPT partition code EF00) 13 | 14 | ## Information you need 15 | ### dev_path 16 | The boot disk device path. This should be the path to the DISK and not a partition. So ```/dev/sda``` may be correct, but ```/dev/sda1``` is wrong 17 | 18 | ### root_partition 19 | The path to where your partition is. It may be something like ```/dev/sda1``` 20 | 21 | 22 | 23 | This program must be run as root. 24 | 25 | ``` 26 | ./make_bootable.py 27 | [sudo] password for sundar: 28 | Usage: make_bootable.py dev_path root_partition [nombr] 29 | 30 | dev_path: full path to disk (e.g. /dev/sdh} 31 | root_partition: root partition path (e.g. /dev/sdh3) 32 | 33 | nombr: if third argument is nombr, then grub-mbr is NOT 34 | installed to MBR EVEN if BIOS partition is present 35 | 36 | 37 | Following are available disks 38 | Disk path RM Model-Serial-Rev 39 | /dev/nvme0n1 N Samsung_SSD_960_EVO_250GB S3ESNX0HB04042L 1B7QCXE7 40 | /dev/sda N Hitachi_HDS72105 A3EA 41 | /dev/sdp Y Store_n_Go_Drive 1100 42 | /dev/sds Y Voyager 1100 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/multiboot_install_grub.md: -------------------------------------------------------------------------------- 1 | # multiboot_install_grub.py 2 | 3 | This script updates grub on a multiboot disk (or ANY disk that has 4 | an EFI partition and a 'bios' partition of type EF02. 5 | Partitions andpartition table are not affected and ONLY grub and EFI files are 6 | updated. 7 | 8 | This program must be run as root. 9 | ``` 10 | Usage: multiboot_install_grub.py dev_path 11 | 12 | dev_path: full path to disk (e.g. /dev/sdh} 13 | 14 | Following are available disks 15 | Disk path RM Model-Serial-Rev 16 | /dev/nvme0n1 N Samsung_SSD_960_EVO_250GB S3ESNX0HB04042L 1B7QCXE7 17 | /dev/sda N Hitachi_HDS72105 A3EA 18 | /dev/sdp Y Store_n_Go_Drive 1100 19 | /dev/sds Y Voyager 1100 20 | ``` 21 | 22 | Upon choosing a disk, you will see output like the following: 23 | 24 | ``` 25 | # ./multiboot_install_grub.py /dev/sds 26 | Scanning partitions on /dev/sds 27 | Confirm disk to update grub. Data will not be affected /dev/sds 28 | 29 | 30 | Model: Corsair Voyager (scsi) 31 | Disk /dev/sds: 8020MB 32 | Sector size (logical/physical): 512B/512B 33 | Partition Table: gpt 34 | Disk Flags:Disk /dev/sds: 15663104 sectors, 7.5 GiB 35 | Logical sector size: 512 bytes 36 | Disk identifier (GUID): 8943D01D-3963-460C-8B69-D52642E3BEAB 37 | Partition table holds up to 128 entries 38 | First usable sector is 34, last usable sector is 15663070 39 | Partitions will be aligned on 2048-sector boundaries 40 | Total free space is 2014 sectors (1007.0 KiB) 41 | Removable: True 42 | Disk Model-Rev: Voyager 1100 43 | 44 | Num Start End Size Code Name FS Path 45 | 1 2048 43007 21.0MB EF02 BIOSGRUB /dev/sds1 46 | 2 43008 15663070 7997MB EF00 EFI vfat /dev/sds2 47 | 48 | Enter "YES" to confirm: 49 | YES 50 | MountedDir: Executing: mount /dev/sds2 /media/tmp_MountedDir_71gV4K 51 | MountedDir: Executing: umount /media/tmp_MountedDir_71gV4K 52 | MountedDir: Executing: mount /dev/sds2 /media/tmp_MountedDir_8daITL 53 | Installing for i386-pc platform. 54 | Installation finished. No error reported. 55 | MountedDir: Executing: umount /media/tmp_MountedDir_8daITL 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/multiboot_update_config.md: -------------------------------------------------------------------------------- 1 | # multiboot_update_config.py 2 | 3 | This script updates grub.cfg based on all ISO images found in ISO dir on the multiboot disk image. 4 | 5 | This program must be run as root. 6 | ``` 7 | Usage: multiboot_update_config.py dev_path 8 | 9 | dev_path: full path to disk (e.g. /dev/sdh} 10 | 11 | Following are available disks 12 | Disk path RM Model-Serial-Rev 13 | /dev/nvme0n1 N Samsung_SSD_960_EVO_250GB S3ESNX0HB04042L 1B7QCXE7 14 | /dev/sda N Hitachi_HDS72105 A3EA 15 | /dev/sdp Y Store_n_Go_Drive 1100 16 | /dev/sds Y Voyager 1100 17 | ``` 18 | 19 | Upon choosing a disk, you will see output like the following: 20 | 21 | ``` 22 | # ./multiboot_install_grub.py /dev/sds 23 | Scanning partitions on /dev/sds 24 | Confirm disk to update grub. Data will not be affected /dev/sds 25 | 26 | 27 | Model: Corsair Voyager (scsi) 28 | Disk /dev/sds: 8020MB 29 | Sector size (logical/physical): 512B/512B 30 | Partition Table: gpt 31 | Disk Flags:Disk /dev/sds: 15663104 sectors, 7.5 GiB 32 | Logical sector size: 512 bytes 33 | Disk identifier (GUID): 8943D01D-3963-460C-8B69-D52642E3BEAB 34 | Partition table holds up to 128 entries 35 | First usable sector is 34, last usable sector is 15663070 36 | Partitions will be aligned on 2048-sector boundaries 37 | Total free space is 2014 sectors (1007.0 KiB) 38 | Removable: True 39 | Disk Model-Rev: Voyager 1100 40 | 41 | Num Start End Size Code Name FS Path 42 | 1 2048 43007 21.0MB EF02 BIOSGRUB /dev/sds1 43 | 2 43008 15663070 7997MB EF00 EFI vfat /dev/sds2 44 | 45 | Enter "YES" to confirm: 46 | YES 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/tree.txt: -------------------------------------------------------------------------------- 1 | bootutils ---------- TOPLEVEL DIR 2 | │ 3 | ├── scripts -------- Boot-disk related 4 | │ Contains remaster_iso_functions.sh, ubuntu_remaster_iso.sh 5 | │ Need to be copied / symlinked under remaster/chroot if desired 6 | │ 7 | │ 8 | └── remaster 9 | ├── chroot ----- Everything under this is copied under /.remaster in squashfs 10 | │   │ and /.remaster/toplevel.sh is executed in CHROOT which will run 11 | │   │ all executable files under /.remaster/commands in lexicographic 12 | │   │ order 13 | │   │ if /.remaster/commands/commands.list is present only executable files 14 | │   │ under /.remaster/commands listed in /.remaster/commands/commands.list 15 | │   │ are executed. /.remaster/commands/commands.list is NEVER executed - 16 | │   │ even if present and executable 17 | │   │ 18 | │   │ /.remaster will be deleted after this step - anything that needs 19 | │   │ to be kept needs to be copied by a script under /.remaster/commands 20 | │   │ 21 | │   │ 22 | │   ├── commands 23 | │   │   ├── commands.list 24 | │   │   ├── 01_install_firmware.sh 25 | │   │   ├── 02_install_kernels.sh 26 | │   │   ├── 03_remove_old_kernels.sh 27 | │   │   ├── 04_install_r8723_bluetooth.sh 28 | │   │   ├── 05_update_all_packages.sh 29 | │   │   └── 06_copy_scripts.sh 30 | │   │ 31 | │   │ 32 | │   ├── firmware - example (used by 01_install_firmware.sh) 33 | │   │ 34 | │   ├── kernel-debs - example (used by 01_install_kernels.sh) 35 | │   │ 36 | │   ├── r8723bs-bluetooth - example (used by 01_install_r8723_bluetooth.sh) 37 | │   │ 38 | │   └── scripts - example (used by 01_copy_scripts.sh) 39 | │ 40 | │ 41 | ├── iso_post ---- Everything in this directory is copied under /.remaster in ISO 42 | │ │ extract directory. This is done AFTER executing under chroot 43 | │ │ OVERWRITING (but NOT deleting) anything that may have been in 44 | │ │ that dir after running iso_pre. /.remaster/toplevel.sh is 45 | │ │ executed, which will run all executable files under 46 | │ │ /.remaster/commands in lexicographic order 47 | │  │ if /.remaster/commands/commands.list is present only executable files 48 | │   │ under /.remaster/commands listed in /.remaster/commands/commands.list 49 | │   │ are executed. /.remaster/commands/commands.list is NEVER executed - 50 | │   │ even if present and executable 51 | │   │ 52 | │   │ /.remaster will be deleted after this step - anything that needs 53 | │   │ to be kept needs to be copied by a script under /.remaster/commands 54 | │   │ 55 | │ │ 56 | │ ├── commands 57 | │   │ ├── 01_iso_kernel.sh 58 | │ │ └── 02_update_efi.sh 59 | │ │ 60 | │ └── efi - example used by 02_update_efi.sh 61 | │ 62 | │ 63 | └── iso_pre ----- Everything in this directory is copied under /.remaster in ISO 64 |    │ This is done BEFORE executing under chroot 65 |    │ /.remaster/toplevel.sh is, which will run all executable files under 66 |    │ /.remaster/commands in lexicographic order 67 |    │ if /.remaster/commands/commands.list is present only executable files 68 |    │ under /.remaster/commands listed in /.remaster/commands/commands.list 69 |    │ are executed. /.remaster/commands/commands.list is NEVER executed - 70 |    │ even if present and executable 71 |    │ 72 |    │ /.remaster will NOT be deleted after this step - will be deleted 73 |    │ after iso_post step 74 |    │ 75 | │ 76 | └── commands 77 | -------------------------------------------------------------------------------- /notes/distrolinks.txt: -------------------------------------------------------------------------------- 1 | Ubuntu - 2x (amd64, i386) for each 2 | Download URL: http://mirror.pnl.gov/releases/ 3 | Grub_config: http://git.marmotte.net/git/glim/tree/grub2/inc-ubuntu.cfg 4 | 5 | Main Ubuntu (Unity) 6 | Ubuntu server 7 | 8 | OFFICIAL Ubuntu flavours 9 | Kubuntu 10 | Lubuntu 11 | Ubuntu Gnome 12 | Ubuntu Mate 13 | Xubuntu 14 | 15 | Ignored: Edubuntu, Mythbuntu, UbuntuKylin, UbuntuStudio 16 | 17 | Ubuntu derivatives 18 | Linuxmint - 2x (amd64, i386) for each 19 | Download URL: https://www.linuxmint.com/download.php 20 | Grub_config: http://git.marmotte.net/git/glim/tree/grub2/inc-linuxmint.cfg 21 | Cinnamon 22 | MATE 23 | Xfce 24 | KDE 25 | 26 | Ignored: LMDE (LinuxMint Debian Edition) 27 | 28 | GRML - 2x (amd64, i386) for each 29 | Download URL: https://grml.org/download/ 30 | Grub_config: http://git.marmotte.net/git/glim/tree/grub2/inc-grml.cfg 31 | About BOOTID: http://ml.grml.org/pipermail/grml/2010-July/010998.html 32 | grml-full 33 | grml-small 34 | 35 | Knoppix - 2x (amd64, i386) for each 36 | Download URL: http://mirrors.sonic.net/knoppix/ 37 | Grub_config: http://git.marmotte.net/git/glim/tree/grub2/inc-knoppix.cfg 38 | CD 39 | DVD 40 | 41 | Debian - 2x (amd64, i386) for each 42 | Download URL: http://cdimage.debian.org/debian-cd/current/amd64/iso-cd/ 43 | Grub_config: http://git.marmotte.net/git/glim/tree/grub2/inc-debian.cfg 44 | KDE 45 | LXDE 46 | XFCE 47 | 48 | Arch 49 | Download URL: https://mirrors.kernel.org/archlinux/ 50 | Grub_config: http://git.marmotte.net/git/glim/tree/grub2/inc-arch.cfg 51 | 52 | Fedora 53 | Download URL: https://getfedora.org/en/workstation/download/ 54 | Download URL: https://mirrors.kernel.org/fedora/releases/ 55 | Grub_config: http://git.marmotte.net/git/glim/tree/grub2/inc-fedora.cfg 56 | 64-bit Live 57 | 32-bit Live 58 | 59 | Manjaro (Arch derivative) - 2x (amd64, i386) for each 60 | Download URL: https://manjaro.org/get-manjaro/ 61 | XFCE 62 | KDE 63 | Gnome 64 | 65 | Antergos (Arch derivative) 66 | Download URL: https://www.antergos.com/try-it/ 67 | 68 | Sabayon (Gentoo derivative) 69 | Download URL: http://www.sabayon.org/download 70 | 71 | Small size distributions 72 | PuppyLinux (Debian-derivative) 73 | Download URL: http://www.puppylinux.com/download 74 | 75 | TinyCoreLinux (Debian-derivative) 76 | Download URL: http://wiki.tinycorelinux.net/wiki:mirrors 77 | 78 | Special Purpose: 79 | KaliLinux (Debian-derivative, forensic-focussed) 80 | Download URL: http://www.kali.org/downloads/ 81 | 82 | TailsOS (Debian-based, privacy-focussed) 83 | Download URL: https://tails.boum.org/download/ 84 | 85 | BackBox (Ubuntu-based forensic-focussed) 86 | Download URL: http://www.backbox.org/downloads 87 | 88 | Parrot Security OS (Debian-based, security-oriented) 89 | Download URL: https://www.parrotsec.org/download.fx 90 | 91 | Free-software only distributions 92 | Trisquel GNU/Linux (Ubuntu-based) 93 | Download URL: http://trisquel.info/download 94 | 95 | gnewsense (Debian-based. sponsored by FSF) 96 | Download URL: http://www.gnewsense.org/Mirrors 97 | 98 | Distros without grub recipes 99 | OpenSuse 100 | Download URL: https://mirrors.kernel.org/opensuse/ 101 | Tumbleweed 102 | amd64 103 | x86 104 | Stable - amd64 only 105 | 106 | Centos - AMD64 only 107 | Download URL: https://mirrors.kernel.org/centos/ 108 | 109 | Gentoo 110 | Download URL: https://gentoo.osuosl.org/releases/ 111 | AMD64 112 | x86 113 | 114 | 115 | -------------------------------------------------------------------------------- /notes/efibootmgr.txt: -------------------------------------------------------------------------------- 1 | 2 | Showing boot entries: 3 | 4 | efibootmgr -v 5 | 6 | 7 | Delete a boot entry 8 | 9 | efibootmgr -b -B 10 | 11 | Add a boot entry: 12 | 13 | efibootmgr 14 | -c (create) 15 | -d (e.g. /dev/sda) 16 | -l (e.g. /EFI/Ubuntu/grubia32.efi) 17 | -L 18 | -p 1 (partition number) 19 | -w (write signature) 20 | 21 | efi_app_file path can use forward (/) or back (\) slashes 22 | If using back (\) slashes, MUST escape EACH one as TWO (\\) 23 | back slashes 24 | 25 | efi_app_file can be ALL UPPER CASE _OR_ actual case 26 | 27 | -------------------------------------------------------------------------------- /notes/grubinstall.txt: -------------------------------------------------------------------------------- 1 | grub packages: 2 | 3 | grub-mkdevicemap: from package grub-common 4 | grub-mkconfig: from package grub-common 5 | grub-mkimage: from package grub-common 6 | grub-mkstandalone from package grub-common 7 | grub-install: from package grub2-common 8 | 9 | /usr/lib/grub/i386-efi from package grub-efi-ia32-bin 10 | /usr/lib/grub/x86_64-efi from package grub-efi-amd64-bin 11 | /usr/lib/grub/i386-pc from package grub-pc-bin (useless for EFI) 12 | 13 | BEFORE doing grub-install: 14 | 15 | sudo apt-get install grub-efi-ia32-bin grub-efi-amd64-bin grub-efi-amd64-signed 16 | # NOTE: DO NOT include grub-efi-ia32 - this will cause removal of 17 | grub-efi-amd64 grub-efi-amd64-signed 18 | 19 | grub-mkdevicemap # Creates / updates /boot/grub/device.map 20 | 21 | # Only add kernels from THIS disk 22 | chmod -x /etc/grub.d/30_os-prober 23 | 24 | grub-mkconfig -m /boot/grub/grub.cfg 25 | 26 | grub-install 27 | --target=i386-efi # critical - EFI and not PC 28 | 29 | --efi-directory=/boot/efi # Could be a different mounted dir? 30 | 31 | --bootloader-id=XXX_ubuntu # optional - defaults to Linux 32 | 33 | /dev/boot/drive # e.g. /dev/sda 34 | 35 | 36 | grub-install will AUTOMATICALLY add the new boot entry to the bootloader 37 | 38 | AFTER grub-install as above: 39 | 40 | mkdir -p /boot/efi/EFI/BOOT 41 | cp /boot/efi/EFI//grubia32.efi /boot/efi/EFI/BOOT/bootia32.efi 42 | 43 | Without /boot/efi/EFI/BOOT/bootia32.efi, will not appear as boot candidate! 44 | 45 | 46 | Make standalone grub2 EFI images: 47 | -------------------------------- 48 | grub-mkstandalone 49 | --format={i386-efi|x86_64-efi} 50 | --output=/EFI/BOOT/boot{ia32|x64}.efi 51 | "/boot/grub.cfg=$CFG" # CFG is embedded grub config file path 52 | 53 | Standalone grub2 EFI images do NOT 'know' which drive they were invoked from 54 | Variables set in such images are ONLY: 55 | 56 | color_highlight=XXXX 57 | color_normal=YYYY 58 | 59 | feature_200_final=y 60 | feature_chainloader_bpb=y 61 | feature_default_font_path=y 62 | feature_menuentry_id=y 63 | feature_menuentry_options=y 64 | feature_nativedisk_cmd=y 65 | feature_ntldr=y 66 | feature_platform_search_hint=y 67 | feature_timeout_style=y 68 | 69 | grub_cpu=x86_64 70 | grub_platform=efi 71 | lang= 72 | locale_dir= 73 | pager= 74 | prefix=(memdisk/boot/grub 75 | root=memdisk 76 | secondary_locale_dir= 77 | 78 | 79 | Links: 80 | ----- 81 | Excellent grub2 shell troubleshooting guide: 82 | https://help.ubuntu.com/community/Grub2/Troubleshooting 83 | 84 | GRUB2 Manual: 85 | https://www.gnu.org/software/grub/manual/grub.html 86 | 87 | GRUB2 tutorial by dedoimedo: 88 | http://www.dedoimedo.com/computers/grub-2.html 89 | 90 | Description of grub2 emulator (package grub-emu): 91 | http://blog.fpmurphy.com/2010/06/grub2-modules.html 92 | -------------------------------------------------------------------------------- /remaster/chroot/commands/02_install_kernels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script ASSUMES a Debian-derived distro (that uses dpkg, apt-get) 3 | # It also assumes Ubuntu-like initramfs commands / config 4 | 5 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 6 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 7 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 8 | REMASTER_DIR=/root/remaster 9 | 10 | KERNEL_DEB_DIR=${PROG_DIR}/../kernel-debs 11 | 12 | if [ ! -d ${KERNEL_DEB_DIR} ]; then 13 | echo "KERNEL_DEB_DIR not a directory: $KERNEL_DEB_DIR" 14 | exit 0 15 | fi 16 | KERNEL_DEB_DIR=$(readlink -e $KERNEL_DEB_DIR) 17 | if [ -z "S(ls -A ${KERNEL_DEB_DIR}/*.deb 2>/dev/null)" ]; then 18 | echo "No deb files in $KERNEL_DEB_DIR" 19 | exit 0 20 | fi 21 | KP_LIST=kernel_pkgs.list 22 | KP_LIST=${KERNEL_DEB_DIR}/$KP_LIST 23 | 24 | if [ -x /etc/grub.d/30_os-prober ]; then 25 | chmod -x /etc/grub.d/30_os-prober 26 | fi 27 | dpkg -i ${KERNEL_DEB_DIR}/*.deb 2>/dev/null 28 | echo overlay >> /etc/initramfs-tools/modules 29 | update-initramfs -u 2>/dev/null 30 | 31 | rm -f ${KP_LIST} 32 | for f in ${KERNEL_DEB_DIR}/*.deb 33 | do 34 | dpkg-deb -f $f Package >> ${KP_LIST} 35 | done 36 | if [ -f ${KP_LIST} ]; then 37 | echo "New kernel packages installed:" 38 | cat ${KP_LIST} | sed -u -e 's/^/ /' 39 | mkdir -p $REMASTER_DIR 40 | cp ${KP_LIST} ${REMASTER_DIR}/ 41 | fi 42 | -------------------------------------------------------------------------------- /remaster/chroot/commands/03_remove_old_kernels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script ASSUMES a Debian-derived distro (that uses dpkg, apt-get) 3 | 4 | # This script is a bit Ubuntu-specific 5 | # Specifically, the names of kernel packages are Ubuntu-specific 6 | # In Ubuntu (and Ubuntu flavours and derivatives), we look for: 7 | # linux-image* linux-headers* linux-signed-image-generic linux-generic 8 | # This may be different in other Debian distros 9 | 10 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 11 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 12 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 13 | 14 | KERNEL_DEB_DIR=${PROG_DIR}/../kernel-debs 15 | 16 | if [ ! -d ${KERNEL_DEB_DIR} ]; then 17 | echo "KERNEL_DEB_DIR not a directory: $KERNEL_DEB_DIR" 18 | exit 0 19 | fi 20 | KERNEL_DEB_DIR=$(readlink -e $KERNEL_DEB_DIR) 21 | KP_LIST=${KERNEL_DEB_DIR}/kernel_pkgs.list 22 | 23 | if [ ! -f $KP_LIST ]; then 24 | echo "kernel_pkgs.list not found: $KP_LIST" 25 | exit 0 26 | fi 27 | 28 | # First check that all new kernel packages are actually installed 29 | for p in $(cat $KP_LIST) 30 | do 31 | inst=$(dpkg -l $p 2>/dev/null | grep '^ii' | awk '{print $2}') 32 | if [ "$p" != "$inst" ]; then 33 | echo "Expected package not installed: $p" 34 | echo "Not uninstalling anything" 35 | exit 0 36 | fi 37 | done 38 | 39 | # Remove kernel-related packages EXCEPT those in $KP_LIST 40 | REMOVE_LIST="" 41 | for p in $(dpkg -l 'linux-image*' | grep '^ii' | awk '{print $2}') 42 | do 43 | fgrep -qx $p $KP_LIST 44 | if [ $? -ne 0 ]; then 45 | REMOVE_LIST="$REMOVE_LIST $p" 46 | fi 47 | done 48 | for p in $(dpkg -l 'linux-headers*' | grep '^ii' | awk '{print $2}') 49 | do 50 | fgrep -qx $p $KP_LIST 51 | if [ $? -ne 0 ]; then 52 | REMOVE_LIST="$REMOVE_LIST $p" 53 | fi 54 | done 55 | for p in linux-signed-image-generic linux-generic 56 | do 57 | fgrep -qx $p $KP_LIST 58 | if [ $? -ne 0 ]; then 59 | REMOVE_LIST="$REMOVE_LIST $p" 60 | fi 61 | done 62 | 63 | if [ -n "$REMOVE_LIST" ]; then 64 | echo "Removing following packages: $REMOVE_LIST" 65 | sudo apt-get autoremove -y --purge $REMOVE_LIST 2>/dev/null 66 | else 67 | echo "No kernel packages to remove" 68 | fi 69 | 70 | echo "Kernel-related packages remaining:" 71 | dpkg -l 'linux-image*' 'linux-headers*' linux-signed-image-generic linux-generic 2>/dev/null | grep '^ii' | awk '{print $2}' | sed -u -e 's/^/ /' 72 | -------------------------------------------------------------------------------- /remaster/chroot/commands/05_update_all_packages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 3 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 4 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 5 | 6 | (apt-get update && apt-get -y upgrade && apt-get dist-upgrade -y) 1>/dev/null 7 | -------------------------------------------------------------------------------- /remaster/chroot/commands/06_install_grub_packages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 3 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 4 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 5 | 6 | apt-get update 1>/dev/null 7 | apt-get -y install grub-efi-ia32-bin grub-efi-amd64-bin grub-pc-bin 1>/dev/null 8 | if [ $? -ne 0 ]; then 9 | apt-get -f install 10 | fi 11 | -------------------------------------------------------------------------------- /remaster/chroot/commands/07_apt_cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 3 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 4 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 5 | 6 | apt-get clean 7 | apt-get autoclean 8 | apt-get -y autoremove --purge 9 | -------------------------------------------------------------------------------- /remaster/chroot/commands/08_copy_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 3 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 4 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 5 | 6 | REMASTER_DIR=/root/remaster 7 | 8 | 9 | SCRIPTS_DIR=${PROG_DIR}/../scripts 10 | if [ ! -d ${SCRIPTS_DIR} ]; then 11 | echo "SCRIPTS_DIR not a directory: $SCRIPTS_DIR" 12 | exit 0 13 | fi 14 | SCRIPTS_DIR=$(readlink -e $SCRIPTS_DIR) 15 | 16 | \cp -r $SCRIPTS_DIR ${REMASTER_DIR}/ 17 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/__boot_grub_mkconfig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Move /boot around and then run grub-mkconfig and restore /boot 3 | 4 | 5 | if [ -z "$1" ]; then 6 | echo "Usage $(basename $0) " 7 | echo " BOOT_PATITION: block device" 8 | exit 1 9 | fi 10 | 11 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 12 | PROG_NAME=$(basename ${PROG_PATH}) 13 | BOOT_PARTITION=$1 14 | 15 | cd / 16 | MOVED_BOOT_DIR=$(mktemp -d -p . "moved_boot_XXXXXXXX") 17 | TEMP_BOOT_DIR=$(mktemp -d -p . "temp_boot_XXXXXXXX") 18 | 19 | mv /boot $MOVED_BOOT_DIR/ 20 | 21 | mount $BOOT_PARTITION ${TEMP_BOOT_DIR} 22 | if [ $? -ne 0 ]; then 23 | echo "mount $BOOT_PARTITION boot failed" 24 | cd /media 25 | umount ${CHROOT_DIR} 26 | exit 1 27 | fi 28 | ln -s ${TEMP_BOOT_DIR}/boot /boot 29 | if [ ! -d boot/grub ]; then 30 | mkdir -p boot/grub 31 | if [ $? -ne 0 ]; then 32 | echo "${CHROOT_DIR}/boot/grub not found and cannot be created" 33 | exit 1 34 | fi 35 | fi 36 | grub-mkconfig > /boot/grub/grub.cfg 37 | 38 | cd / 39 | rm -rf /boot 40 | umount ${TEMP_BOOT_DIR} 41 | rmdir ${TEMP_BOOT_DIR} 42 | mv $MOVED_BOOT_DIR/boot / 43 | rmdir $MOVED_BOOT_DIR 44 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/__chroot_grub_mkconfig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "Usage $(basename $0) " 5 | echo " ROOT_PATITION: block device" 6 | exit 1 7 | fi 8 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 9 | PROG_NAME=$(basename ${PROG_PATH}) 10 | ROOT_PARTITION=$1 11 | 12 | 13 | CHROOT_DIR=$(mktemp -d -p /media "tmp_${PROG_NAME}_XXXXXXXX") 14 | echo "CHROOT_DIR: ${CHROOT_DIR}" 15 | 16 | mount $ROOT_PARTITION $CHROOT_DIR 17 | if [ $? -ne 0 ]; then 18 | echo "mount $ROOT_PARTITION $CHROOT_DIR failed" 19 | exit 1 20 | fi 21 | sleep 5 22 | 23 | if [ ! -d "${CHROOT_DIR}"/boot/grub ]; then 24 | mkdir -p /boot/grub 25 | if [ $? -ne 0 ]; then 26 | echo "${CHROOT_DIR}/boot/grub not found and cannot be created" 27 | exit 1 28 | fi 29 | fi 30 | 31 | for d in run proc sys dev dev/pts 32 | do 33 | mount --bind /$d ${CHROOT_DIR}/$d 34 | done 35 | 36 | chroot ${CHROOT_DIR} <<+ 37 | grub-mkconfig > /boot/grub/grub.cfg 38 | + 39 | 40 | for d in run proc sys dev/pts dev 41 | do 42 | umount ${CHROOT_DIR}/$d 43 | done 44 | 45 | sleep 2 46 | umount "${CHROOT_DIR}" 47 | sleep 2 48 | \rm -rf ${CHROOT_DIR} 49 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/__remaster_toplevel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Executes all executable files in directory 'commands' in the same 4 | # directory as this script in lexicographic order 5 | # 6 | # If 'commands' directory contains a file named 'commands.list', then 7 | # that file is expected to contain filenames within 'commands' dir 8 | # to be executed. In that case, ONLY files in commands.list that 9 | # are executable are executed in the order they appear in 10 | # commands.list 11 | # 12 | # commands.list is NEVER executed, even if present and executable 13 | 14 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 15 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 16 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 17 | 18 | if [ -n "$REMASTER_STAGE" ]; then 19 | STAGE="[$REMASTER_STAGE]" 20 | else 21 | STAGE="" 22 | fi 23 | 24 | COMMANDS_DIR=${PROG_DIR}/commands 25 | if [ ! -d $COMMANDS_DIR ]; then 26 | echo "${PROG_NAME}: COMMANDS_DIR not a directory: $COMMANDS_DIR ${STAGE}" 27 | exit 0 28 | fi 29 | COMMANDS_DIR=$(readlink -e $COMMANDS_DIR) 30 | 31 | if [ -f ${COMMANDS_DIR}/commands.list ]; then 32 | CMD_LIST=$(cat ${COMMANDS_DIR}/command.list) 33 | if [ -z "$CMD_LIST" ]; then 34 | echo "${PROG_NAME}: Empty commands.list. Ignoring commands in $COMMANDS_DIR ${STAGE}" 35 | exit 0 36 | fi 37 | echo "${PROG_NAME}: Only running specified commands in commands.list" 38 | else 39 | CMD_LIST=$(ls ${COMMANDS_DIR}) 40 | if [ -z "$CMD_LIST" ]; then 41 | echo "${PROG_NAME}: No commands found in $COMMANDS_DIR ${STAGE}" 42 | exit 0 43 | fi 44 | fi 45 | 46 | for f in $CMD_LIST 47 | do 48 | f=$(basename $f) # In case commands.list contained paths 49 | if [ "$f" = "commands.list" ]; then 50 | continue 51 | fi 52 | CMD=${COMMANDS_DIR}/$f 53 | 54 | if [ ! -x ${CMD} ]; then 55 | echo "${CMD} ${STAGE}: Ignoring non-executable file" 56 | fi 57 | echo "$(basename $CMD) ${STAGE}: Starting" 58 | $CMD 2>&1 | sed -u -e 's/^/ /' 59 | if [ $? -ne 0 ]; then 60 | echo "$(basename $CMD) ${STAGE}: Non-zero return code" 61 | fi 62 | echo "$(basename $CMD) ${STAGE}: Completed" 63 | done 64 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/bootdisk_create.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | from common_utils import require_root_or_exit 5 | from efiutils import ( 6 | DiskDetails, 7 | show_available_disks, 8 | erase_partition_table, 9 | ) 10 | 11 | 12 | if __name__ == '__main__': 13 | require_root_or_exit() 14 | if len(sys.argv) < 2: 15 | print('Usage: %s dev_path boot_dir' % ( 16 | os.path.basename(sys.argv[0]), 17 | )) 18 | print('') 19 | print('dev_path: path to disk (e.g. /dev/sdh}') 20 | print('boot_dir: path to copy boot files from') 21 | print('') 22 | print('Following are available disks') 23 | show_available_disks() 24 | exit(1) 25 | boot_dev = sys.argv[1] 26 | boot_dir = sys.argv[2] 27 | msg = 'Confirm destroying all partitions and data on %s' % (sys.argv[1],) 28 | try: 29 | d = DiskDetails(boot_dev) 30 | resp = d.confirm_action(msg) 31 | except: 32 | resp = erase_partition_table(boot_dev) 33 | if not resp: 34 | exit(0) 35 | d = DiskDetails(boot_dev) 36 | d.bootdisk_erase_create() 37 | boot_partition = d.partitions[-1].path 38 | d.bootdisk_populate_update_cfg( 39 | boot_partition=boot_partition, boot_dir=boot_dir) 40 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/erase_initialize_disk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from common_utils import require_root_or_exit 4 | from efiutils import DiskDetails, show_available_disks, erase_partition_table 5 | 6 | if __name__ == '__main__': 7 | require_root_or_exit() 8 | if len(sys.argv) < 2: 9 | print('Usage: create_efi.py dev_path [nombr]') 10 | print('') 11 | print('dev_path: full path to disk (e.g. /dev/sdh)') 12 | print('nombr: if parameter present, BIOS partition is NOT created') 13 | print('') 14 | print('If second parameter is missing or anything other than nombr') 15 | print('BIOS partition is created for compatibility with grub-mbr') 16 | print('') 17 | print('Following are available disks') 18 | show_available_disks() 19 | exit(1) 20 | 21 | need_bios_partition = True 22 | if len(sys.argv) > 2: 23 | need_bios_partition = (sys.argv[2] != 'nombr') 24 | msg = 'Confirm destroying all partitions and data on %s' % (sys.argv[1],) 25 | try: 26 | d = DiskDetails(sys.argv[1]) 27 | resp = d.confirm_action(msg) 28 | except: 29 | resp = erase_partition_table(sys.argv[1]) 30 | if not resp: 31 | exit(0) 32 | d = DiskDetails(sys.argv[1]) 33 | d.erase_disk() 34 | d.create_efi_partition(bios_partition=need_bios_partition) 35 | print(d) 36 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/grub_embedded.cfg: -------------------------------------------------------------------------------- 1 | # Add line above: set efi_fs_uuid = UUID of EFI partition 2 | # We look for config called grub_fs_uuid.cfg in rootdir of EFI partition 3 | 4 | # ------------------------------------------------------------------------ 5 | # Should not have to change anything below this 6 | # ------------------------------------------------------------------------ 7 | 8 | insmod memdisk 9 | insmod part_gpt 10 | 11 | function load_video { 12 | # To avoid errors that look like: 13 | # no suitable video mode found; booting in blind mode 14 | terminal_input console 15 | terminal_output console 16 | 17 | if [ x$feature_all_video_module = xy ]; then 18 | insmod all_video 19 | else 20 | insmod efi_gop 21 | insmod efi_uga 22 | insmod ieee1275_fb 23 | insmod vbe 24 | insmod vga 25 | insmod video_bochs 26 | insmod video_cirrus 27 | fi 28 | } 29 | 30 | function load_grub_cfg { 31 | # Set root before calling this function 32 | # If grub.cfg was successfully loaded, will not return 33 | 34 | # Keep cfg_prefix as /boot/grub so that grub-EFI and grub-MBR can share the same 35 | # config. grub-MBR cannot contain an embedded config and always looks for 36 | # /boot/grub/grub.cfg 37 | set cfg_prefix=/boot/grub 38 | set cfgfile=grub.cfg 39 | set cfgpath=$cfg_prefix/$cfgfile 40 | if [ -f $cfgpath ]; then 41 | configfile $cfgpath 42 | fi 43 | } 44 | 45 | function error_no_grub_cfg { 46 | # Give up, but give user a more helpful message if cfg file is not found 47 | echo "" 48 | echo "# ------------------------------------------------------------------------" 49 | echo "Config file was not found: $cfgpath" 50 | echo "" 51 | echo "TWO steps to manually locate and load config file:" 52 | echo "1. Define root" 53 | echo "use set root command to set root" 54 | echo " Use ls to show partitions and directories / files" 55 | echo "" 56 | echo "2. Load config file and return to menu" 57 | echo " configfile ($root)/full/path/to/config" 58 | echo " Use TAB to autocomplete" 59 | echo "# ------------------------------------------------------------------------" 60 | echo "" 61 | } 62 | 63 | function error_no_uuid_cfg { 64 | # Give up, tell user where grub_fs_uuid.cfg should be and what it contains 65 | echo "" 66 | echo "# ------------------------------------------------------------------------" 67 | echo "UUID config file was not found: $cfgpath" 68 | echo "This file should be called $cfgfile and should be in root of" 69 | echo "EFI partition" 70 | echo "It should contain one line defining variable grubfs_uuid" 71 | echo "to be UUID of partition containing /boot/grub/grub.cfg" 72 | echo "" 73 | echo "# ------------------------------------------------------------------------" 74 | echo "" 75 | } 76 | 77 | load_video 78 | 79 | search --fs-uuid --set=root $efi_fs_uuid 80 | set cfgfile="grub_fs_uuid.cfg" 81 | set cfgpath=/$cfgfile 82 | 83 | if [ -f $cfgpath ]; then 84 | source $cfgpath 85 | search --fs-uuid --set=root $grub_fs_uuid 86 | load_grub_cfg 87 | # If we got here, grub.cfg file was not found 88 | error_no_grub_cfg 89 | else 90 | # Try with root set from efi_fs_uuid - e.g. multiboot disks 91 | search --fs-uuid --set=root $efi_fs_uuid 92 | load_grub_cfg 93 | # If we got here, grub.cfg file was not found 94 | error_no_grub_cfg 95 | error_no_uuid_cfg 96 | fi 97 | echo "Press RETURN to continue" 98 | read 99 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/install_grub_pkgs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt-get update && \ 4 | apt-get -y install grub-efi-ia32-bin grub-efi-amd64-bin 5 | if [ $? -ne 0 ]; then 6 | apt-get -f install 7 | fi 8 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/isoparser/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from . import iso, source 3 | 4 | 5 | def parse(path_or_url, cache_content=False, min_fetch=16): 6 | """ 7 | Returns an :class:`ISO` object for the given filesystem path or URL. 8 | 9 | cache_content: 10 | Whether to store sectors backing file content in the sector cache. If true, this will 11 | cause memory usage to grow to the size of the ISO as more file content get accessed. 12 | Even if false (default), an individual Record object will cache its own file content 13 | for the lifetime of the Record, once accessed. 14 | 15 | min_fetch: 16 | The smallest number of sectors to fetch in a single operation, to speed up sequential 17 | accesses, e.g. for directory traversal. Defaults to 16 sectors, or 32 KiB. 18 | """ 19 | if path_or_url.startswith("http"): 20 | src = source.HTTPSource(path_or_url, cache_content=cache_content, min_fetch=min_fetch) 21 | else: 22 | src = source.FileSource(path_or_url, cache_content=cache_content, min_fetch=min_fetch) 23 | return iso.ISO(src) 24 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/isoparser/iso.py: -------------------------------------------------------------------------------- 1 | from . import susp, rockridge 2 | 3 | 4 | class ISO(object): 5 | def __init__(self, source): 6 | self._source = source 7 | 8 | # Unpack volume descriptors 9 | self.volume_descriptors = {} 10 | sector = 16 11 | while True: 12 | self._source.seek(sector) 13 | sector += 1 14 | 15 | vd = self._source.unpack_volume_descriptor() 16 | self.volume_descriptors[vd.name] = vd 17 | 18 | if vd.name == "terminator": 19 | break 20 | 21 | # Unpack the path table 22 | self._source.seek( 23 | self.volume_descriptors['primary'].path_table_l_loc, 24 | self.volume_descriptors['primary'].path_table_size) 25 | self.path_table = self._source.unpack_path_table() 26 | 27 | # Save a reference to the root record 28 | self.root = self.volume_descriptors['primary'].root_record 29 | 30 | # Check to see if SUSP is enabled 31 | root_record = self.root.current_directory 32 | if root_record.embedded_susp_entries and isinstance(root_record.embedded_susp_entries[0], susp.SP): 33 | self._source.susp_starting_index = root_record.embedded_susp_entries[0].len_skp 34 | self._source.susp_extensions = [e for e in root_record.susp_entries if isinstance(e, susp.ER)] 35 | if any(((er.ext_id, er.ext_ver) in rockridge.EXT_VERSIONS) for er in self._source.susp_extensions): 36 | self._source.rockridge = True 37 | else: 38 | self._source.susp_starting_index = False 39 | 40 | def __enter__(self): 41 | return self 42 | 43 | def __exit__(self, exc_type, exc_val, exc_tb): 44 | self.close() 45 | 46 | def close(self): 47 | self._source.close() 48 | 49 | def record(self, *path): 50 | """ 51 | Retrieves a record for the given path. 52 | """ 53 | record = None 54 | if self._source.rockridge: 55 | # In Rock Ridge mode, we can't use the path table 56 | pivot = 0 57 | else: 58 | path = [part.upper() for part in path] 59 | pivot = len(path) 60 | 61 | 62 | # Resolve as much of the path as possible via the path table 63 | while pivot > 0: 64 | try: 65 | record = self.path_table.record(*path[:pivot]) 66 | except KeyError: 67 | pivot -= 1 68 | else: 69 | break 70 | 71 | if record is None: 72 | record = self.root 73 | 74 | # Resolve the remainder of the path by walking record children 75 | for part in path[pivot:]: 76 | for child in record.children_unsafe: 77 | # Must save the cursor since child.name can cause a seek 78 | saved_cursor = self._source.save_cursor() 79 | if child.name == part: 80 | record = child 81 | break 82 | self._source.restore_cursor(saved_cursor) 83 | else: 84 | raise KeyError(part) 85 | 86 | return record 87 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/isoparser/path_table.py: -------------------------------------------------------------------------------- 1 | from . import record 2 | 3 | 4 | class PathTable(object): 5 | def __init__(self, source): 6 | self._source = source 7 | self.paths = {} 8 | 9 | paths_list = [] 10 | 11 | while len(source) > 0: 12 | name_length = source.unpack('B') 13 | _ = source.unpack('B') 14 | location = source.unpack(' 0: 21 | path.extend(paths_list[parent_idx]) 22 | if name != "\x00": 23 | path.append(name) 24 | 25 | paths_list.append(path) 26 | self.paths[tuple(path)] = location 27 | 28 | def record(self, *path): 29 | location = self.paths[path] 30 | self._source.seek(location) 31 | return self._source.unpack_record() -------------------------------------------------------------------------------- /remaster/chroot/scripts/isoparser/rockridge.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from .susp import SUSP_Entry, susp_assert 3 | 4 | RRIP_109 = ('RRIP_1991A', 1) 5 | RRIP_112 = ('IEEE_P1282', 1) 6 | 7 | EXT_VERSIONS = (RRIP_109, RRIP_112) 8 | 9 | class RR(SUSP_Entry): 10 | _implements = [ 11 | RRIP_109 + ('RR', 1), 12 | ] 13 | 14 | PX = 1 15 | PN = 2 16 | SL = 4 17 | NM = 8 18 | CL = 16 19 | PL = 32 20 | RE = 64 21 | TF = 128 22 | 23 | _repr_props = ('flags',) 24 | 25 | def __init__(self, source, ext_id_ver, sig_version, length): 26 | super(RR, self).__init__(source, ext_id_ver, sig_version, length) 27 | susp_assert(length == 1) 28 | self.flags = source.unpack('B') 29 | 30 | class PX(SUSP_Entry): 31 | _implements = [ 32 | RRIP_109 + ('PX', 1), 33 | RRIP_112 + ('PX', 1), 34 | ] 35 | 36 | _repr_props = ('mode','nlinks','uid','gid') 37 | 38 | def __init__(self, source, ext_id_ver, sig_version, length): 39 | super(PX, self).__init__(source, ext_id_ver, sig_version, length) 40 | susp_assert(length in (32, 40)) 41 | self.mode = source.unpack_both('I') 42 | self.nlinks = source.unpack_both('I') 43 | self.uid = source.unpack_both('I') 44 | self.gid = source.unpack_both('I') 45 | self.ino = source.unpack_both('I') if length >= 40 else None 46 | 47 | class PN(SUSP_Entry): 48 | _implements = [ 49 | RRIP_109 + ('PN', 1), 50 | RRIP_112 + ('PN', 1), 51 | ] 52 | 53 | _repr_props = ('dev_high', 'dev_low') 54 | 55 | def __init__(self, source, ext_id_ver, sig_version, length): 56 | super(PN, self).__init__(source, ext_id_ver, sig_version, length) 57 | susp_assert(length == 16) 58 | self.dev_high = source.unpack_both('I') 59 | self.dev_low = source.unpack_both('I') 60 | 61 | class SL(SUSP_Entry): 62 | _implements = [ 63 | RRIP_109 + ('SL', 1), 64 | RRIP_112 + ('SL', 1), 65 | ] 66 | 67 | CONTINUE = 1 68 | CURRENT = 2 69 | PARENT = 4 70 | ROOT = 8 71 | 72 | _repr_props = ('flags', 'path') 73 | 74 | def __init__(self, source, ext_id_ver, sig_version, length): 75 | super(SL, self).__init__(source, ext_id_ver, sig_version, length) 76 | susp_assert(length >= 2) # Needs SL flags and at least one component 77 | target = source.cursor + length 78 | self.flags = source.unpack('B') 79 | self.path = b"" 80 | while source.cursor < target: 81 | comp_flags = source.unpack('B') 82 | comp_len = source.unpack('B') 83 | comp_content = source.unpack_raw(comp_len) 84 | susp_assert(source.cursor <= target) 85 | if comp_flags == SL.CURRENT: 86 | susp_assert(comp_len == 0) 87 | self.path += b"." 88 | elif comp_flags == SL.PARENT: 89 | susp_assert(comp_len == 0) 90 | self.path += b".." 91 | elif comp_flags == SL.ROOT: 92 | susp_assert(comp_len == 0) 93 | elif comp_flags in (0, SL.CONTINUE): 94 | susp_assert(comp_len > 0) 95 | self.path += comp_content 96 | else: 97 | susp_assert(False) # Unknown SL flags 98 | 99 | if comp_flags == SL.CONTINUE: 100 | # If this is a root component or an unfinished component, don't append a / 101 | pass 102 | elif comp_flags == 0 and source.cursor == target and (self.flags & SL.CONTINUE == 0): 103 | # If this is the last component in the link, don't append a / 104 | pass 105 | else: 106 | # Otherwise, append a / 107 | self.path += b"/" 108 | 109 | class NM(SUSP_Entry): 110 | _implements = [ 111 | RRIP_109 + ('NM', 1), 112 | RRIP_112 + ('NM', 1), 113 | ] 114 | 115 | _repr_props = ('flags', 'name') 116 | 117 | CONTINUE = 1 118 | CURRENT = 2 119 | PARENT = 4 120 | 121 | def __init__(self, source, ext_id_ver, sig_version, length): 122 | super(NM, self).__init__(source, ext_id_ver, sig_version, length) 123 | susp_assert(length >= 1) 124 | self.flags = source.unpack('B') 125 | name_content = source.unpack_raw(length - 1) 126 | if self.flags == NM.CURRENT: 127 | susp_assert(length == 1) 128 | self.name = "." 129 | elif self.flags == NM.PARENT: 130 | susp_assert(length == 1) 131 | self.name = ".." 132 | elif self.flags in (0, NM.CONTINUE): 133 | susp_assert(length > 1) 134 | self.name = name_content 135 | 136 | class TF(SUSP_Entry): 137 | _implements = [ 138 | RRIP_109 + ('TF', 1), 139 | RRIP_112 + ('TF', 1), 140 | ] 141 | 142 | _repr_props = ('flags', 'creation', 'modify', 'access', 'attributes', 'backup', 'expiration', 'effective') 143 | 144 | CREATION = 1 145 | MODIFY = 2 146 | ACCESS = 4 147 | ATTRIBUTES = 8 148 | BACKUP = 16 149 | EXPIRATION = 32 150 | EFFECTIVE = 64 151 | LONG_FORM = 128 152 | 153 | def __init__(self, source, ext_id_ver, sig_version, length): 154 | super(TF, self).__init__(source, ext_id_ver, sig_version, length) 155 | susp_assert(length >= 1) 156 | self.flags = source.unpack('B') 157 | if self.flags & TF.LONG_FORM: 158 | unpack_datetime = source.unpack_vd_datetime 159 | else: 160 | unpack_datetime = source.unpack_dir_datetime 161 | 162 | self.creation = unpack_datetime() if self.flags & TF.CREATION else None 163 | self.modify = unpack_datetime() if self.flags & TF.MODIFY else None 164 | self.access = unpack_datetime() if self.flags & TF.ACCESS else None 165 | self.attributes = unpack_datetime() if self.flags & TF.ATTRIBUTES else None 166 | self.backup = unpack_datetime() if self.flags & TF.BACKUP else None 167 | self.expiration = unpack_datetime() if self.flags & TF.EXPIRATION else None 168 | self.effective = unpack_datetime() if self.flags & TF.EFFECTIVE else None 169 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/isoparser/susp.py: -------------------------------------------------------------------------------- 1 | from six import add_metaclass, iteritems 2 | 3 | class SUSPError(Exception): 4 | pass 5 | 6 | def susp_assert(condition): 7 | if not condition: 8 | raise SUSPError("Failed SUSP assertion") 9 | 10 | class susp_meta(type): 11 | def __new__(mcs, name, bases, dict): 12 | cls = type.__new__(mcs, name, bases, dict) 13 | if '_implements' in dict: 14 | for i in dict['_implements']: 15 | SUSP_Entry._registered_classes[i] = cls 16 | return cls 17 | 18 | @add_metaclass(susp_meta) 19 | class SUSP_Entry(object): 20 | _registered_classes = {} 21 | _repr_props = () 22 | 23 | @classmethod 24 | def unpack(cls, source, ext_id_ver, sig_version, length): 25 | implementing_class = None 26 | if ext_id_ver: 27 | implementing_class = cls._registered_classes.get(ext_id_ver + sig_version) 28 | if not implementing_class: 29 | ext_id_ver = None 30 | implementing_class = cls._registered_classes.get(sig_version, UnknownEntry) 31 | return implementing_class(source, ext_id_ver, sig_version, length) 32 | 33 | def __init__(self, source, ext_id_ver, sig_version, length): 34 | self.ext_id_ver = ext_id_ver 35 | self.sig_version = sig_version 36 | self.signature, self.version = sig_version 37 | 38 | def __repr__(self): 39 | return "" % ( 40 | self.signature, self.version, 41 | ''.join(" %s=%s" % (k,repr(v)) for k,v in self._repr_keyvals)) 42 | 43 | @property 44 | def _repr_keyvals(self): 45 | for prop in self._repr_props: 46 | yield prop, getattr(self, prop) 47 | 48 | class UnknownEntry(SUSP_Entry): 49 | def __init__(self, source, ext_id_ver, sig_version, length): 50 | super(UnknownEntry, self).__init__(source, ext_id_ver, sig_version, length) 51 | self.unknown_raw = source.unpack_raw(length) 52 | 53 | @property 54 | def _repr_keyvals(self): 55 | return iteritems({'unknown/length': len(self.unknown_raw)+4}) 56 | 57 | class SP(SUSP_Entry): 58 | _implements = [ 59 | ('SP', 1), 60 | ] 61 | 62 | _repr_props = ('len_skp',) 63 | 64 | def __init__(self, source, ext_id_ver, sig_version, length): 65 | super(SP, self).__init__(source, ext_id_ver, sig_version, length) 66 | susp_assert(length == 3) 67 | susp_assert(source.unpack_raw(2) == b"\xbe\xef") 68 | self.len_skp = source.unpack('B') 69 | 70 | class CE(SUSP_Entry): 71 | _implements = [ 72 | ('CE', 1), 73 | ] 74 | 75 | _repr_props = ('location', 'offset', 'length') 76 | 77 | def __init__(self, source, ext_id_ver, sig_version, length): 78 | super(CE, self).__init__(source, ext_id_ver, sig_version, length) 79 | susp_assert(length == 24) 80 | self.location = source.unpack_both('I') 81 | self.offset = source.unpack_both('I') 82 | self.length = source.unpack_both('I') 83 | 84 | class PD(SUSP_Entry): 85 | _implements = [ 86 | ('PD', 1), 87 | ] 88 | 89 | def __init__(self, source, ext_id_ver, sig_version, length): 90 | super(PD, self).__init__(source, ext_id_ver, sig_version, length) 91 | if length: 92 | source.unpack_raw(length) # Padding, ignored 93 | 94 | class ST(SUSP_Entry): 95 | _implements = [ 96 | ('ST', 1), 97 | ] 98 | 99 | def __init__(self, source, ext_id_ver, sig_version, length): 100 | super(ST, self).__init__(source, ext_id_ver, sig_version, length) 101 | susp_assert(length == 0) 102 | 103 | class ER(SUSP_Entry): 104 | _implements = [ 105 | ('ER', 1), 106 | ] 107 | 108 | _repr_props = ('ext_id', 'ext_ver') 109 | 110 | def __init__(self, source, ext_id_ver, sig_version, length): 111 | super(ER, self).__init__(source, ext_id_ver, sig_version, length) 112 | susp_assert(length >= 4) 113 | len_id = source.unpack('B') 114 | len_des = source.unpack('B') 115 | len_src = source.unpack('B') 116 | susp_assert(length == 4 + len_id + len_des + len_src) 117 | self.ext_ver = source.unpack('B') 118 | self.ext_id = source.unpack_raw(len_id).decode() 119 | self.ext_des = source.unpack_raw(len_des).decode() 120 | self.ext_src = source.unpack_raw(len_src).decode() 121 | 122 | class ES(SUSP_Entry): 123 | _implements = [ 124 | ('ES', 1), 125 | ] 126 | 127 | _repr_props = ('ext_seq',) 128 | 129 | def __init__(self, source, ext_id_ver, sig_version, length): 130 | super(ER, self).__init__(source, ext_id_ver, sig_version, length) 131 | susp_assert(length == 1) 132 | self.ext_seq = source.unpack('B') 133 | 134 | from . import rockridge 135 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/isoparser/volume_descriptors.py: -------------------------------------------------------------------------------- 1 | class VolumeDescriptor(object): 2 | name = None 3 | 4 | def __init__(self, source): 5 | pass 6 | 7 | def __repr__(self): 8 | return "" % self.name 9 | 10 | 11 | class BootVD(VolumeDescriptor): 12 | name = "boot" 13 | 14 | 15 | class PrimaryVD(VolumeDescriptor): 16 | name = "primary" 17 | 18 | def __init__(self, source): 19 | super(PrimaryVD, self).__init__(source) 20 | 21 | _ = source.unpack_raw(1) # unused 22 | self.system_identifier = source.unpack_string(32) 23 | self.volume_identifier = source.unpack_string(32) 24 | _ = source.unpack_raw(8) # unused 25 | self.volume_space_size = source.unpack_both('i') 26 | _ = source.unpack_raw(32) # unused 27 | self.volume_set_size = source.unpack_both('h') 28 | self.volume_seq_num = source.unpack_both('h') 29 | self.logical_block_size = source.unpack_both('h') 30 | self.path_table_size = source.unpack_both('i') 31 | self.path_table_l_loc = source.unpack('i') 34 | self.path_table_opt_m_loc = source.unpack('>i') 35 | self.root_record = source.unpack_record() 36 | self.volume_set_identifier = source.unpack_string(128) 37 | self.publisher_identifier = source.unpack_string(128) 38 | self.data_preparer_identifier = source.unpack_string(128) 39 | self.application_identifier = source.unpack_string(128) 40 | self.copyright_file_identifier = source.unpack_string(38) 41 | self.abstract_file_identifier = source.unpack_string(36) 42 | self.bibliographic_file_identifier = source.unpack_string(37) 43 | self.volume_datetime_created = source.unpack_vd_datetime() 44 | self.volume_datetime_modified = source.unpack_vd_datetime() 45 | self.volume_datetime_expires = source.unpack_vd_datetime() 46 | self.volume_datetime_effective = source.unpack_vd_datetime() 47 | self.file_structure_version = source.unpack('B') 48 | 49 | 50 | class SupplementaryVD(VolumeDescriptor): 51 | name = "supplementary" 52 | 53 | 54 | class PartitionVD(VolumeDescriptor): 55 | name = "partition" 56 | 57 | 58 | class TerminatorVD(VolumeDescriptor): 59 | name = "terminator" -------------------------------------------------------------------------------- /remaster/chroot/scripts/make_bootable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | from common_utils import require_root_or_exit 5 | from efiutils import ( 6 | DiskDetails, 7 | update_fstab_boot_efi, 8 | show_available_disks, 9 | ) 10 | 11 | 12 | if __name__ == '__main__': 13 | require_root_or_exit() 14 | if len(sys.argv) < 3: 15 | print('Usage: %s dev_path root_partition [nombr]' % ( 16 | os.path.basename(sys.argv[0]),)) 17 | print('') 18 | print(' dev_path: full path to disk (e.g. /dev/sdh}') 19 | print(' root_partition: root partition path (e.g. /dev/sdh3)') 20 | print('') 21 | print(' nombr: if third argument is nombr, then grub-mbr is NOT ') 22 | print(' installed to MBR EVEN if BIOS partition is present') 23 | print('') 24 | print('Following are available disks') 25 | show_available_disks() 26 | exit(1) 27 | boot_dev = sys.argv[1] 28 | root_partition = sys.argv[2] 29 | update_mbr = True 30 | if len(sys.argv) > 3: 31 | update_mbr = (sys.argv[3] != 'nombr') 32 | 33 | d = DiskDetails(boot_dev) 34 | partnum = d.partnum_by_path(root_partition) 35 | msg = 'Confirm disk. Data will not be affected %s' % (d.devpath,) 36 | if d.confirm_action(msg, partnum): 37 | d.make_bootable(root_partition, update_mbr) 38 | update_fstab_boot_efi(boot_dev, root_partition) 39 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/multiboot_create.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | from common_utils import require_root_or_exit 5 | from efiutils import ( 6 | DiskDetails, 7 | show_available_disks, 8 | erase_partition_table, 9 | ) 10 | 11 | 12 | if __name__ == '__main__': 13 | require_root_or_exit() 14 | if len(sys.argv) < 2: 15 | print('Usage: %s dev_path' % (os.path.basename(sys.argv[0]),)) 16 | print('') 17 | print('dev_path: full path to disk (e.g. /dev/sdh}') 18 | print('') 19 | print('Following are available disks') 20 | show_available_disks() 21 | exit(1) 22 | 23 | msg = 'Confirm destroying all partitions and data on %s' % (sys.argv[1],) 24 | try: 25 | d = DiskDetails(sys.argv[1]) 26 | resp = d.confirm_action(msg) 27 | except: 28 | resp = erase_partition_table(sys.argv[1]) 29 | if not resp: 30 | exit(0) 31 | d = DiskDetails(sys.argv[1]) 32 | d.multiboot_erase_create() 33 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/multiboot_install_grub.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | from common_utils import require_root_or_exit 5 | from efiutils import ( 6 | DiskDetails, 7 | show_available_disks, 8 | ) 9 | 10 | 11 | if __name__ == '__main__': 12 | require_root_or_exit() 13 | if len(sys.argv) < 2: 14 | print('Usage: %s dev_path' % (os.path.basename(sys.argv[0]),)) 15 | print('') 16 | print(' dev_path: full path to disk (e.g. /dev/sdh}') 17 | print('') 18 | print('Following are available disks') 19 | show_available_disks() 20 | exit(1) 21 | d = DiskDetails(sys.argv[1]) 22 | msg = 'Confirm disk to update grub. Data will not be affected %s' % ( 23 | d.devpath,) 24 | if d.confirm_action(msg): 25 | d.multiboot_instal_grub() 26 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/multiboot_update_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | from common_utils import require_root_or_exit 5 | from efiutils import ( 6 | DiskDetails, 7 | show_available_disks, 8 | ) 9 | 10 | 11 | if __name__ == '__main__': 12 | require_root_or_exit() 13 | if len(sys.argv) < 2: 14 | print('Usage: %s dev_path' % (os.path.basename(sys.argv[0]),)) 15 | print('') 16 | print(' dev_path: full path to disk (e.g. /dev/sdh}') 17 | print('') 18 | print('Following are available disks') 19 | show_available_disks() 20 | exit(1) 21 | d = DiskDetails(sys.argv[1]) 22 | msg = ('Confirm disk to update grub config. ' 23 | 'Data will not be affected %s') % (d.devpath,) 24 | if d.confirm_action(msg): 25 | d.multiboot_update_config() 26 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/pkgs_missing_from.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | REQD_PKGS="$*" 3 | 4 | MISSING_PKGS=$(dpkg -l $REQD_PKGS | sed -e '1,4d'| grep -v '^ii' | awk '{printf("%s ", $2)}') 5 | if [ -n "${MISSING_PKGS%% }" ]; then 6 | INSTALL_CMD="sudo apt-get install $MISSING_PKGS" 7 | else 8 | INSTALL_CMD="All required packages are already installed\nRequired packages: $REQD_PKGS" 9 | fi 10 | echo $INSTALL_CMD 11 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/required_pkgs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | REQD_PKGS="grub-efi-ia32-bin grub-efi-amd64-bin grub-pc-bin grub2-common grub-common util-linux parted gdisk mount xorriso genisoimage squashfs-tools rsync" 3 | 4 | MISSING_PKGS=$(dpkg -l $REQD_PKGS | sed -e '1,4d'| grep -v '^ii' | awk '{printf("%s ", $2)}') 5 | if [ -n "${MISSING_PKGS%% }" ]; then 6 | INSTALL_CMD="sudo apt-get install $MISSING_PKGS" 7 | else 8 | INSTALL_CMD="All required packages are already installed\nRequired packages: $REQD_PKGS" 9 | fi 10 | echo -e "$INSTALL_CMD" 11 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/show_disks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from common_utils import require_root_or_exit 3 | from efiutils import show_available_disks 4 | 5 | if __name__ == '__main__': 6 | require_root_or_exit() 7 | show_available_disks() 8 | -------------------------------------------------------------------------------- /remaster/chroot/scripts/show_iso_details.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | from linuxiso import get_instance 5 | 6 | if __name__ == '__main__': 7 | if len(sys.argv) < 2: 8 | print('Usage: %s " 7 | echo " BOOT_PATITION: block device" 8 | exit 1 9 | fi 10 | 11 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 12 | PROG_NAME=$(basename ${PROG_PATH}) 13 | BOOT_PARTITION=$1 14 | 15 | cd / 16 | MOVED_BOOT_DIR=$(mktemp -d -p . "moved_boot_XXXXXXXX") 17 | TEMP_BOOT_DIR=$(mktemp -d -p . "temp_boot_XXXXXXXX") 18 | 19 | mv /boot $MOVED_BOOT_DIR/ 20 | 21 | mount $BOOT_PARTITION ${TEMP_BOOT_DIR} 22 | if [ $? -ne 0 ]; then 23 | echo "mount $BOOT_PARTITION boot failed" 24 | cd /media 25 | umount ${CHROOT_DIR} 26 | exit 1 27 | fi 28 | ln -s ${TEMP_BOOT_DIR}/boot /boot 29 | if [ ! -d boot/grub ]; then 30 | mkdir -p boot/grub 31 | if [ $? -ne 0 ]; then 32 | echo "${CHROOT_DIR}/boot/grub not found and cannot be created" 33 | exit 1 34 | fi 35 | fi 36 | grub-mkconfig > /boot/grub/grub.cfg 37 | 38 | cd / 39 | rm -rf /boot 40 | umount ${TEMP_BOOT_DIR} 41 | rmdir ${TEMP_BOOT_DIR} 42 | mv $MOVED_BOOT_DIR/boot / 43 | rmdir $MOVED_BOOT_DIR 44 | -------------------------------------------------------------------------------- /scripts/__chroot_grub_mkconfig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "Usage $(basename $0) " 5 | echo " ROOT_PATITION: block device" 6 | exit 1 7 | fi 8 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 9 | PROG_NAME=$(basename ${PROG_PATH}) 10 | ROOT_PARTITION=$1 11 | 12 | 13 | CHROOT_DIR=$(mktemp -d -p /media "tmp_${PROG_NAME}_XXXXXXXX") 14 | echo "CHROOT_DIR: ${CHROOT_DIR}" 15 | 16 | mount $ROOT_PARTITION $CHROOT_DIR 17 | if [ $? -ne 0 ]; then 18 | echo "mount $ROOT_PARTITION $CHROOT_DIR failed" 19 | exit 1 20 | fi 21 | sleep 5 22 | 23 | if [ ! -d "${CHROOT_DIR}"/boot/grub ]; then 24 | mkdir -p /boot/grub 25 | if [ $? -ne 0 ]; then 26 | echo "${CHROOT_DIR}/boot/grub not found and cannot be created" 27 | exit 1 28 | fi 29 | fi 30 | 31 | for d in run proc sys dev dev/pts 32 | do 33 | mount --bind /$d ${CHROOT_DIR}/$d 34 | done 35 | 36 | chroot ${CHROOT_DIR} <<+ 37 | grub-mkconfig > /boot/grub/grub.cfg 38 | + 39 | 40 | for d in run proc sys dev/pts dev 41 | do 42 | umount ${CHROOT_DIR}/$d 43 | done 44 | 45 | sleep 2 46 | umount "${CHROOT_DIR}" 47 | sleep 2 48 | \rm -rf ${CHROOT_DIR} 49 | -------------------------------------------------------------------------------- /scripts/__remaster_toplevel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Executes all executable files in directory 'commands' in the same 4 | # directory as this script in lexicographic order 5 | # 6 | # If 'commands' directory contains a file named 'commands.list', then 7 | # that file is expected to contain filenames within 'commands' dir 8 | # to be executed. In that case, ONLY files in commands.list that 9 | # are executable are executed in the order they appear in 10 | # commands.list 11 | # 12 | # commands.list is NEVER executed, even if present and executable 13 | # 14 | # TODOs 15 | # 1. IGNORE user command filenames that start with underscore 16 | # 2. Create __remaster_toplevel_functions.sh with common functions 17 | # Export functions using 'export -f ' 18 | # See: https://unix.stackexchange.com/a/22867 19 | # 3. Copy __remaster_toplevel_functions.sh to same dir as 20 | # __remaster_toplevel.sh in run_remaster_commands function 21 | # in __remaster_toplevel_functions.sh 22 | # 23 | # 4. Use common functions in user scripts: 24 | # a. initialize 25 | # Setup /etc/resolv.conf and create /etc/resolv.conf.remaster_orig 26 | # b. check_pkg_integrity 27 | # c. install_if_missing 28 | # Install list of packages permanently in chroot 29 | # use check_pkg_integrity 30 | # d. install_pkgs_temporary 31 | # Install list of packages, but mark them to be removed 32 | # at the end of chroot commands 33 | # use check_pkg_integrity 34 | # e. run_cmd_if_available 35 | # f. run_cmd_or_exit 36 | # Exits from script if command is UNAVAILABLE 37 | # g. run_cmd_or_fail 38 | # Exits remastering processif command is UNAVAILABLE 39 | # h. require_dir_or_exit 40 | # i. require_file_or_exit 41 | # j. require_dir_or_fail 42 | # k. require_file_or_fail 43 | 44 | # 5. Create new automatic (non-user) commands 45 | # a. __apt_update 46 | # run apt-update - need to do only once in chroot 47 | # b. __remove_temporary_packages - at the end of chroot commands 48 | # 6. Change __remaster_toplevel.sh to: 49 | # a. Run __apt_update BEFORE any user commands 50 | # b. Run __remove_temporary_packages AFTER ALL user commands 51 | # 7. Change user commands 52 | # a. Add xx_install_packages - at the start - use install_if_missing 53 | 54 | 55 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 56 | PROG_DIR=${PROG_DIR:-$(dirname ${PROG_PATH})} 57 | PROG_NAME=${PROG_NAME:-$(basename ${PROG_PATH})} 58 | FAILED_EXIT_CODE=127 59 | 60 | if [ -n "$REMASTER_STAGE" ]; then 61 | STAGE="[$REMASTER_STAGE]" 62 | else 63 | STAGE="" 64 | fi 65 | 66 | COMMANDS_DIR=${PROG_DIR}/commands 67 | if [ ! -d $COMMANDS_DIR ]; then 68 | echo "${PROG_NAME}: Not a directory: $COMMANDS_DIR ${STAGE}" 69 | exit 0 70 | fi 71 | COMMANDS_DIR=$(readlink -e $COMMANDS_DIR) 72 | 73 | if [ -f ${COMMANDS_DIR}/commands.list ]; then 74 | CMD_LIST=$(cat ${COMMANDS_DIR}/command.list) 75 | if [ -z "$CMD_LIST" ]; then 76 | echo "${PROG_NAME}: Empty commands.list. Ignoring commands in COMMANDS_DIR ${STAGE}" 77 | exit 0 78 | fi 79 | echo "${PROG_NAME}: Only running specified commands in commands.list ${STAGE}" 80 | else 81 | CMD_LIST=$(ls ${COMMANDS_DIR}) 82 | if [ -z "$CMD_LIST" ]; then 83 | echo "${PROG_NAME}: No commands found: ${STAGE}" 84 | exit 0 85 | fi 86 | fi 87 | 88 | for f in $CMD_LIST 89 | do 90 | f=$(basename $f) # In case commands.list contained paths 91 | if [ "$f" = "commands.list" ]; then 92 | continue 93 | fi 94 | CMD=${COMMANDS_DIR}/$f 95 | 96 | if [ ! -x ${CMD} ]; then 97 | echo "$(basename ${CMD}) ${STAGE}: Ignoring non-executable file" 98 | continue 99 | fi 100 | echo "$(basename $CMD) ${STAGE}: Starting" 101 | $CMD 2>&1 | sed -u -e 's/^/ /' 102 | # Special case if return code is $FAILED_EXIT_CODE, bail out of remaster 103 | ret=$? 104 | if [ $ret -eq $FAILED_EXIT_CODE ]; then 105 | echo "$(basename $CMD) ${STAGE}: Failed - exiting remaster script" 106 | exit 1 107 | elif [ $ret -ne 0 ]; then 108 | echo "$(basename $CMD) ${STAGE}: Non-zero return code" 109 | fi 110 | echo "$(basename $CMD) ${STAGE}: Completed" 111 | done 112 | -------------------------------------------------------------------------------- /scripts/bootdisk_create.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | import os # noqa: E402 5 | from common_utils import require_root_or_exit # noqa: E402 6 | from efiutils import ( 7 | DiskDetails, 8 | show_available_disks, 9 | erase_partition_table, 10 | ) # noqa: E402 11 | 12 | 13 | if __name__ == '__main__': 14 | require_root_or_exit() 15 | if len(sys.argv) < 2: 16 | print('Usage: %s dev_path boot_dir' % ( 17 | os.path.basename(sys.argv[0]), 18 | )) 19 | print('') 20 | print('dev_path: path to disk (e.g. /dev/sdh}') 21 | print('boot_dir: path to copy boot files from') 22 | print('') 23 | print('Following are available disks') 24 | show_available_disks() 25 | exit(1) 26 | boot_dev = sys.argv[1] 27 | boot_dir = sys.argv[2] 28 | msg = 'Confirm destroying all partitions and data on %s' % (sys.argv[1],) 29 | try: 30 | d = DiskDetails(boot_dev) 31 | resp = d.confirm_action(msg) 32 | except: 33 | resp = erase_partition_table(boot_dev) 34 | if not resp: 35 | exit(0) 36 | d = DiskDetails(boot_dev) 37 | d.bootdisk_erase_create() 38 | boot_partition = d.partitions[-1].path 39 | d.bootdisk_populate_update_cfg( 40 | boot_partition=boot_partition, boot_dir=boot_dir) 41 | -------------------------------------------------------------------------------- /scripts/create_efi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PROG_DIR=$(dirname "$BASH_SOURCE") 3 | PROG_DIR=$(readlink -e "$PROG_DIR") 4 | PROG_NAME=$(basename "$BASH_SOURCE") 5 | 6 | source "$PROG_DIR"/efi_functions.sh || { 7 | >&2 echo "Could not source: $PROG_DIR/disk_partition_functions.sh" 8 | exit 1 9 | } 10 | 11 | 12 | create_update_efi $@ 13 | ret=$? 14 | [[ $ret -ne 0 ]] && { 15 | >&2 echo "${PROG_NAME} : create_update_efi failed: Return code: $ret" 16 | exit $ret 17 | } 18 | -------------------------------------------------------------------------------- /scripts/erase_initialize_disk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | from common_utils import require_root_or_exit # noqa: E402 5 | from efiutils import ( 6 | DiskDetails, show_available_disks, erase_partition_table 7 | ) # noqa: E402 8 | 9 | if __name__ == '__main__': 10 | require_root_or_exit() 11 | if len(sys.argv) < 2: 12 | print('Usage: create_efi.py dev_path [nombr]') 13 | print('') 14 | print('dev_path: full path to disk (e.g. /dev/sdh)') 15 | print('nombr: if parameter present, BIOS partition is NOT created') 16 | print('') 17 | print('If second parameter is missing or anything other than nombr') 18 | print('BIOS partition is created for compatibility with grub-mbr') 19 | print('') 20 | print('Following are available disks') 21 | show_available_disks() 22 | exit(1) 23 | 24 | need_bios_partition = True 25 | if len(sys.argv) > 2: 26 | need_bios_partition = (sys.argv[2] != 'nombr') 27 | msg = 'Confirm destroying all partitions and data on %s' % (sys.argv[1],) 28 | try: 29 | d = DiskDetails(sys.argv[1]) 30 | resp = d.confirm_action(msg) 31 | except: 32 | resp = erase_partition_table(sys.argv[1]) 33 | if not resp: 34 | exit(0) 35 | d = DiskDetails(sys.argv[1]) 36 | d.erase_disk() 37 | d.create_efi_partition(bios_partition=need_bios_partition) 38 | print(d) 39 | -------------------------------------------------------------------------------- /scripts/grub_embedded.cfg: -------------------------------------------------------------------------------- 1 | # Add line above: set efi_fs_uuid = UUID of EFI partition 2 | # We look for config called grub_fs_uuid.cfg in rootdir of EFI partition 3 | 4 | # ------------------------------------------------------------------------ 5 | # Should not have to change anything below this 6 | # ------------------------------------------------------------------------ 7 | 8 | insmod memdisk 9 | insmod part_gpt 10 | 11 | function load_video { 12 | # To avoid errors that look like: 13 | # no suitable video mode found; booting in blind mode 14 | terminal_input console 15 | terminal_output console 16 | 17 | if [ x$feature_all_video_module = xy ]; then 18 | insmod all_video 19 | else 20 | insmod efi_gop 21 | insmod efi_uga 22 | insmod ieee1275_fb 23 | insmod vbe 24 | insmod vga 25 | insmod video_bochs 26 | insmod video_cirrus 27 | fi 28 | } 29 | 30 | function load_grub_cfg { 31 | # Set root before calling this function 32 | # If grub.cfg was successfully loaded, will not return 33 | 34 | # Keep cfg_prefix as /boot/grub so that grub-EFI and grub-MBR can share the same 35 | # config. grub-MBR cannot contain an embedded config and always looks for 36 | # /boot/grub/grub.cfg 37 | set cfg_prefix=/boot/grub 38 | set cfgfile=grub.cfg 39 | set cfgpath=$cfg_prefix/$cfgfile 40 | if [ -f $cfgpath ]; then 41 | configfile $cfgpath 42 | fi 43 | } 44 | 45 | function error_no_grub_cfg { 46 | # Give up, but give user a more helpful message if cfg file is not found 47 | echo "" 48 | echo "# ------------------------------------------------------------------------" 49 | echo "Config file was not found: $cfgpath" 50 | echo "" 51 | echo "TWO steps to manually locate and load config file:" 52 | echo "1. Define root" 53 | echo "use set root command to set root" 54 | echo " Use ls to show partitions and directories / files" 55 | echo "" 56 | echo "2. Load config file and return to menu" 57 | echo " configfile ($root)/full/path/to/config" 58 | echo " Use TAB to autocomplete" 59 | echo "# ------------------------------------------------------------------------" 60 | echo "" 61 | } 62 | 63 | function error_no_uuid_cfg { 64 | # Give up, tell user where grub_fs_uuid.cfg should be and what it contains 65 | echo "" 66 | echo "# ------------------------------------------------------------------------" 67 | echo "UUID config file was not found: $cfgpath" 68 | echo "This file should be called $cfgfile and should be in root of" 69 | echo "EFI partition" 70 | echo "It should contain one line defining variable grubfs_uuid" 71 | echo "to be UUID of partition containing /boot/grub/grub.cfg" 72 | echo "" 73 | echo "# ------------------------------------------------------------------------" 74 | echo "" 75 | } 76 | 77 | load_video 78 | 79 | search --fs-uuid --set=root $efi_fs_uuid 80 | set cfgfile="grub_fs_uuid.cfg" 81 | set cfgpath=/$cfgfile 82 | 83 | if [ -f $cfgpath ]; then 84 | source $cfgpath 85 | search --fs-uuid --set=root $grub_fs_uuid 86 | load_grub_cfg 87 | # If we got here, grub.cfg file was not found 88 | error_no_grub_cfg 89 | else 90 | # Try with root set from efi_fs_uuid - e.g. multiboot disks 91 | search --fs-uuid --set=root $efi_fs_uuid 92 | load_grub_cfg 93 | # If we got here, grub.cfg file was not found 94 | error_no_grub_cfg 95 | error_no_uuid_cfg 96 | fi 97 | echo "Press RETURN to continue" 98 | read 99 | -------------------------------------------------------------------------------- /scripts/install_grub_pkgs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt-get update && \ 4 | apt-get -y install grub-efi-ia32-bin grub-efi-amd64-bin 5 | if [ $? -ne 0 ]; then 6 | apt-get -f install 7 | fi 8 | -------------------------------------------------------------------------------- /scripts/isoparser/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from . import iso, source 3 | 4 | 5 | def parse(path_or_url, cache_content=False, min_fetch=16): 6 | """ 7 | Returns an :class:`ISO` object for the given filesystem path or URL. 8 | 9 | cache_content: 10 | Whether to store sectors backing file content in the sector cache. If true, this will 11 | cause memory usage to grow to the size of the ISO as more file content get accessed. 12 | Even if false (default), an individual Record object will cache its own file content 13 | for the lifetime of the Record, once accessed. 14 | 15 | min_fetch: 16 | The smallest number of sectors to fetch in a single operation, to speed up sequential 17 | accesses, e.g. for directory traversal. Defaults to 16 sectors, or 32 KiB. 18 | """ 19 | if path_or_url.startswith("http"): 20 | src = source.HTTPSource(path_or_url, cache_content=cache_content, min_fetch=min_fetch) 21 | else: 22 | src = source.FileSource(path_or_url, cache_content=cache_content, min_fetch=min_fetch) 23 | return iso.ISO(src) 24 | -------------------------------------------------------------------------------- /scripts/isoparser/iso.py: -------------------------------------------------------------------------------- 1 | from . import susp, rockridge 2 | 3 | 4 | class ISO(object): 5 | def __init__(self, source): 6 | self._source = source 7 | 8 | # Unpack volume descriptors 9 | self.volume_descriptors = {} 10 | sector = 16 11 | while True: 12 | self._source.seek(sector) 13 | sector += 1 14 | 15 | vd = self._source.unpack_volume_descriptor() 16 | self.volume_descriptors[vd.name] = vd 17 | 18 | if vd.name == "terminator": 19 | break 20 | 21 | # Unpack the path table 22 | self._source.seek( 23 | self.volume_descriptors['primary'].path_table_l_loc, 24 | self.volume_descriptors['primary'].path_table_size) 25 | self.path_table = self._source.unpack_path_table() 26 | 27 | # Save a reference to the root record 28 | self.root = self.volume_descriptors['primary'].root_record 29 | 30 | # Check to see if SUSP is enabled 31 | root_record = self.root.current_directory 32 | if root_record.embedded_susp_entries and isinstance(root_record.embedded_susp_entries[0], susp.SP): 33 | self._source.susp_starting_index = root_record.embedded_susp_entries[0].len_skp 34 | self._source.susp_extensions = [e for e in root_record.susp_entries if isinstance(e, susp.ER)] 35 | if any(((er.ext_id, er.ext_ver) in rockridge.EXT_VERSIONS) for er in self._source.susp_extensions): 36 | self._source.rockridge = True 37 | else: 38 | self._source.susp_starting_index = False 39 | 40 | def __enter__(self): 41 | return self 42 | 43 | def __exit__(self, exc_type, exc_val, exc_tb): 44 | self.close() 45 | 46 | def close(self): 47 | self._source.close() 48 | 49 | def record(self, *path): 50 | """ 51 | Retrieves a record for the given path. 52 | """ 53 | record = None 54 | if self._source.rockridge: 55 | # In Rock Ridge mode, we can't use the path table 56 | pivot = 0 57 | else: 58 | path = [part.upper() for part in path] 59 | pivot = len(path) 60 | 61 | 62 | # Resolve as much of the path as possible via the path table 63 | while pivot > 0: 64 | try: 65 | record = self.path_table.record(*path[:pivot]) 66 | except KeyError: 67 | pivot -= 1 68 | else: 69 | break 70 | 71 | if record is None: 72 | record = self.root 73 | 74 | # Resolve the remainder of the path by walking record children 75 | for part in path[pivot:]: 76 | for child in record.children_unsafe: 77 | # Must save the cursor since child.name can cause a seek 78 | saved_cursor = self._source.save_cursor() 79 | if child.name == part: 80 | record = child 81 | break 82 | self._source.restore_cursor(saved_cursor) 83 | else: 84 | raise KeyError(part) 85 | 86 | return record 87 | -------------------------------------------------------------------------------- /scripts/isoparser/path_table.py: -------------------------------------------------------------------------------- 1 | from . import record 2 | 3 | 4 | class PathTable(object): 5 | def __init__(self, source): 6 | self._source = source 7 | self.paths = {} 8 | 9 | paths_list = [] 10 | 11 | while len(source) > 0: 12 | name_length = source.unpack('B') 13 | _ = source.unpack('B') 14 | location = source.unpack(' 0: 21 | path.extend(paths_list[parent_idx]) 22 | if name != "\x00": 23 | path.append(name) 24 | 25 | paths_list.append(path) 26 | self.paths[tuple(path)] = location 27 | 28 | def record(self, *path): 29 | location = self.paths[path] 30 | self._source.seek(location) 31 | return self._source.unpack_record() -------------------------------------------------------------------------------- /scripts/isoparser/rockridge.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from .susp import SUSP_Entry, susp_assert 3 | 4 | RRIP_109 = ('RRIP_1991A', 1) 5 | RRIP_112 = ('IEEE_P1282', 1) 6 | 7 | EXT_VERSIONS = (RRIP_109, RRIP_112) 8 | 9 | class RR(SUSP_Entry): 10 | _implements = [ 11 | RRIP_109 + ('RR', 1), 12 | ] 13 | 14 | PX = 1 15 | PN = 2 16 | SL = 4 17 | NM = 8 18 | CL = 16 19 | PL = 32 20 | RE = 64 21 | TF = 128 22 | 23 | _repr_props = ('flags',) 24 | 25 | def __init__(self, source, ext_id_ver, sig_version, length): 26 | super(RR, self).__init__(source, ext_id_ver, sig_version, length) 27 | susp_assert(length == 1) 28 | self.flags = source.unpack('B') 29 | 30 | class PX(SUSP_Entry): 31 | _implements = [ 32 | RRIP_109 + ('PX', 1), 33 | RRIP_112 + ('PX', 1), 34 | ] 35 | 36 | _repr_props = ('mode','nlinks','uid','gid') 37 | 38 | def __init__(self, source, ext_id_ver, sig_version, length): 39 | super(PX, self).__init__(source, ext_id_ver, sig_version, length) 40 | susp_assert(length in (32, 40)) 41 | self.mode = source.unpack_both('I') 42 | self.nlinks = source.unpack_both('I') 43 | self.uid = source.unpack_both('I') 44 | self.gid = source.unpack_both('I') 45 | self.ino = source.unpack_both('I') if length >= 40 else None 46 | 47 | class PN(SUSP_Entry): 48 | _implements = [ 49 | RRIP_109 + ('PN', 1), 50 | RRIP_112 + ('PN', 1), 51 | ] 52 | 53 | _repr_props = ('dev_high', 'dev_low') 54 | 55 | def __init__(self, source, ext_id_ver, sig_version, length): 56 | super(PN, self).__init__(source, ext_id_ver, sig_version, length) 57 | susp_assert(length == 16) 58 | self.dev_high = source.unpack_both('I') 59 | self.dev_low = source.unpack_both('I') 60 | 61 | class SL(SUSP_Entry): 62 | _implements = [ 63 | RRIP_109 + ('SL', 1), 64 | RRIP_112 + ('SL', 1), 65 | ] 66 | 67 | CONTINUE = 1 68 | CURRENT = 2 69 | PARENT = 4 70 | ROOT = 8 71 | 72 | _repr_props = ('flags', 'path') 73 | 74 | def __init__(self, source, ext_id_ver, sig_version, length): 75 | super(SL, self).__init__(source, ext_id_ver, sig_version, length) 76 | susp_assert(length >= 2) # Needs SL flags and at least one component 77 | target = source.cursor + length 78 | self.flags = source.unpack('B') 79 | self.path = b"" 80 | while source.cursor < target: 81 | comp_flags = source.unpack('B') 82 | comp_len = source.unpack('B') 83 | comp_content = source.unpack_raw(comp_len) 84 | susp_assert(source.cursor <= target) 85 | if comp_flags == SL.CURRENT: 86 | susp_assert(comp_len == 0) 87 | self.path += b"." 88 | elif comp_flags == SL.PARENT: 89 | susp_assert(comp_len == 0) 90 | self.path += b".." 91 | elif comp_flags == SL.ROOT: 92 | susp_assert(comp_len == 0) 93 | elif comp_flags in (0, SL.CONTINUE): 94 | susp_assert(comp_len > 0) 95 | self.path += comp_content 96 | else: 97 | susp_assert(False) # Unknown SL flags 98 | 99 | if comp_flags == SL.CONTINUE: 100 | # If this is a root component or an unfinished component, don't append a / 101 | pass 102 | elif comp_flags == 0 and source.cursor == target and (self.flags & SL.CONTINUE == 0): 103 | # If this is the last component in the link, don't append a / 104 | pass 105 | else: 106 | # Otherwise, append a / 107 | self.path += b"/" 108 | 109 | class NM(SUSP_Entry): 110 | _implements = [ 111 | RRIP_109 + ('NM', 1), 112 | RRIP_112 + ('NM', 1), 113 | ] 114 | 115 | _repr_props = ('flags', 'name') 116 | 117 | CONTINUE = 1 118 | CURRENT = 2 119 | PARENT = 4 120 | 121 | def __init__(self, source, ext_id_ver, sig_version, length): 122 | super(NM, self).__init__(source, ext_id_ver, sig_version, length) 123 | susp_assert(length >= 1) 124 | self.flags = source.unpack('B') 125 | name_content = source.unpack_raw(length - 1) 126 | if self.flags == NM.CURRENT: 127 | susp_assert(length == 1) 128 | self.name = "." 129 | elif self.flags == NM.PARENT: 130 | susp_assert(length == 1) 131 | self.name = ".." 132 | elif self.flags in (0, NM.CONTINUE): 133 | susp_assert(length > 1) 134 | self.name = name_content 135 | 136 | class TF(SUSP_Entry): 137 | _implements = [ 138 | RRIP_109 + ('TF', 1), 139 | RRIP_112 + ('TF', 1), 140 | ] 141 | 142 | _repr_props = ('flags', 'creation', 'modify', 'access', 'attributes', 'backup', 'expiration', 'effective') 143 | 144 | CREATION = 1 145 | MODIFY = 2 146 | ACCESS = 4 147 | ATTRIBUTES = 8 148 | BACKUP = 16 149 | EXPIRATION = 32 150 | EFFECTIVE = 64 151 | LONG_FORM = 128 152 | 153 | def __init__(self, source, ext_id_ver, sig_version, length): 154 | super(TF, self).__init__(source, ext_id_ver, sig_version, length) 155 | susp_assert(length >= 1) 156 | self.flags = source.unpack('B') 157 | if self.flags & TF.LONG_FORM: 158 | unpack_datetime = source.unpack_vd_datetime 159 | else: 160 | unpack_datetime = source.unpack_dir_datetime 161 | 162 | self.creation = unpack_datetime() if self.flags & TF.CREATION else None 163 | self.modify = unpack_datetime() if self.flags & TF.MODIFY else None 164 | self.access = unpack_datetime() if self.flags & TF.ACCESS else None 165 | self.attributes = unpack_datetime() if self.flags & TF.ATTRIBUTES else None 166 | self.backup = unpack_datetime() if self.flags & TF.BACKUP else None 167 | self.expiration = unpack_datetime() if self.flags & TF.EXPIRATION else None 168 | self.effective = unpack_datetime() if self.flags & TF.EFFECTIVE else None 169 | -------------------------------------------------------------------------------- /scripts/isoparser/susp.py: -------------------------------------------------------------------------------- 1 | from six import add_metaclass, iteritems 2 | 3 | class SUSPError(Exception): 4 | pass 5 | 6 | def susp_assert(condition): 7 | if not condition: 8 | raise SUSPError("Failed SUSP assertion") 9 | 10 | class susp_meta(type): 11 | def __new__(mcs, name, bases, dict): 12 | cls = type.__new__(mcs, name, bases, dict) 13 | if '_implements' in dict: 14 | for i in dict['_implements']: 15 | SUSP_Entry._registered_classes[i] = cls 16 | return cls 17 | 18 | @add_metaclass(susp_meta) 19 | class SUSP_Entry(object): 20 | _registered_classes = {} 21 | _repr_props = () 22 | 23 | @classmethod 24 | def unpack(cls, source, ext_id_ver, sig_version, length): 25 | implementing_class = None 26 | if ext_id_ver: 27 | implementing_class = cls._registered_classes.get(ext_id_ver + sig_version) 28 | if not implementing_class: 29 | ext_id_ver = None 30 | implementing_class = cls._registered_classes.get(sig_version, UnknownEntry) 31 | return implementing_class(source, ext_id_ver, sig_version, length) 32 | 33 | def __init__(self, source, ext_id_ver, sig_version, length): 34 | self.ext_id_ver = ext_id_ver 35 | self.sig_version = sig_version 36 | self.signature, self.version = sig_version 37 | 38 | def __repr__(self): 39 | return "" % ( 40 | self.signature, self.version, 41 | ''.join(" %s=%s" % (k,repr(v)) for k,v in self._repr_keyvals)) 42 | 43 | @property 44 | def _repr_keyvals(self): 45 | for prop in self._repr_props: 46 | yield prop, getattr(self, prop) 47 | 48 | class UnknownEntry(SUSP_Entry): 49 | def __init__(self, source, ext_id_ver, sig_version, length): 50 | super(UnknownEntry, self).__init__(source, ext_id_ver, sig_version, length) 51 | self.unknown_raw = source.unpack_raw(length) 52 | 53 | @property 54 | def _repr_keyvals(self): 55 | return iteritems({'unknown/length': len(self.unknown_raw)+4}) 56 | 57 | class SP(SUSP_Entry): 58 | _implements = [ 59 | ('SP', 1), 60 | ] 61 | 62 | _repr_props = ('len_skp',) 63 | 64 | def __init__(self, source, ext_id_ver, sig_version, length): 65 | super(SP, self).__init__(source, ext_id_ver, sig_version, length) 66 | susp_assert(length == 3) 67 | susp_assert(source.unpack_raw(2) == b"\xbe\xef") 68 | self.len_skp = source.unpack('B') 69 | 70 | class CE(SUSP_Entry): 71 | _implements = [ 72 | ('CE', 1), 73 | ] 74 | 75 | _repr_props = ('location', 'offset', 'length') 76 | 77 | def __init__(self, source, ext_id_ver, sig_version, length): 78 | super(CE, self).__init__(source, ext_id_ver, sig_version, length) 79 | susp_assert(length == 24) 80 | self.location = source.unpack_both('I') 81 | self.offset = source.unpack_both('I') 82 | self.length = source.unpack_both('I') 83 | 84 | class PD(SUSP_Entry): 85 | _implements = [ 86 | ('PD', 1), 87 | ] 88 | 89 | def __init__(self, source, ext_id_ver, sig_version, length): 90 | super(PD, self).__init__(source, ext_id_ver, sig_version, length) 91 | if length: 92 | source.unpack_raw(length) # Padding, ignored 93 | 94 | class ST(SUSP_Entry): 95 | _implements = [ 96 | ('ST', 1), 97 | ] 98 | 99 | def __init__(self, source, ext_id_ver, sig_version, length): 100 | super(ST, self).__init__(source, ext_id_ver, sig_version, length) 101 | susp_assert(length == 0) 102 | 103 | class ER(SUSP_Entry): 104 | _implements = [ 105 | ('ER', 1), 106 | ] 107 | 108 | _repr_props = ('ext_id', 'ext_ver') 109 | 110 | def __init__(self, source, ext_id_ver, sig_version, length): 111 | super(ER, self).__init__(source, ext_id_ver, sig_version, length) 112 | susp_assert(length >= 4) 113 | len_id = source.unpack('B') 114 | len_des = source.unpack('B') 115 | len_src = source.unpack('B') 116 | susp_assert(length == 4 + len_id + len_des + len_src) 117 | self.ext_ver = source.unpack('B') 118 | self.ext_id = source.unpack_raw(len_id).decode() 119 | self.ext_des = source.unpack_raw(len_des).decode() 120 | self.ext_src = source.unpack_raw(len_src).decode() 121 | 122 | class ES(SUSP_Entry): 123 | _implements = [ 124 | ('ES', 1), 125 | ] 126 | 127 | _repr_props = ('ext_seq',) 128 | 129 | def __init__(self, source, ext_id_ver, sig_version, length): 130 | super(ER, self).__init__(source, ext_id_ver, sig_version, length) 131 | susp_assert(length == 1) 132 | self.ext_seq = source.unpack('B') 133 | 134 | from . import rockridge 135 | -------------------------------------------------------------------------------- /scripts/isoparser/volume_descriptors.py: -------------------------------------------------------------------------------- 1 | class VolumeDescriptor(object): 2 | name = None 3 | 4 | def __init__(self, source): 5 | pass 6 | 7 | def __repr__(self): 8 | return "" % self.name 9 | 10 | 11 | class BootVD(VolumeDescriptor): 12 | name = "boot" 13 | 14 | 15 | class PrimaryVD(VolumeDescriptor): 16 | name = "primary" 17 | 18 | def __init__(self, source): 19 | super(PrimaryVD, self).__init__(source) 20 | 21 | _ = source.unpack_raw(1) # unused 22 | self.system_identifier = source.unpack_string(32) 23 | self.volume_identifier = source.unpack_string(32) 24 | _ = source.unpack_raw(8) # unused 25 | self.volume_space_size = source.unpack_both('i') 26 | _ = source.unpack_raw(32) # unused 27 | self.volume_set_size = source.unpack_both('h') 28 | self.volume_seq_num = source.unpack_both('h') 29 | self.logical_block_size = source.unpack_both('h') 30 | self.path_table_size = source.unpack_both('i') 31 | self.path_table_l_loc = source.unpack('i') 34 | self.path_table_opt_m_loc = source.unpack('>i') 35 | self.root_record = source.unpack_record() 36 | self.volume_set_identifier = source.unpack_string(128) 37 | self.publisher_identifier = source.unpack_string(128) 38 | self.data_preparer_identifier = source.unpack_string(128) 39 | self.application_identifier = source.unpack_string(128) 40 | self.copyright_file_identifier = source.unpack_string(38) 41 | self.abstract_file_identifier = source.unpack_string(36) 42 | self.bibliographic_file_identifier = source.unpack_string(37) 43 | self.volume_datetime_created = source.unpack_vd_datetime() 44 | self.volume_datetime_modified = source.unpack_vd_datetime() 45 | self.volume_datetime_expires = source.unpack_vd_datetime() 46 | self.volume_datetime_effective = source.unpack_vd_datetime() 47 | self.file_structure_version = source.unpack('B') 48 | 49 | 50 | class SupplementaryVD(VolumeDescriptor): 51 | name = "supplementary" 52 | 53 | 54 | class PartitionVD(VolumeDescriptor): 55 | name = "partition" 56 | 57 | 58 | class TerminatorVD(VolumeDescriptor): 59 | name = "terminator" -------------------------------------------------------------------------------- /scripts/make_bootable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | import os # noqa: E402 5 | from common_utils import require_root_or_exit # noqa: E402 6 | from efiutils import ( 7 | DiskDetails, 8 | update_fstab_boot_efi, 9 | show_available_disks, 10 | ) # noqa: E402 11 | 12 | 13 | if __name__ == '__main__': 14 | require_root_or_exit() 15 | if len(sys.argv) < 3: 16 | print('Usage: %s dev_path root_partition [nombr]' % ( 17 | os.path.basename(sys.argv[0]),)) 18 | print('') 19 | print(' dev_path: full path to disk (e.g. /dev/sdh}') 20 | print(' root_partition: root partition path (e.g. /dev/sdh3)') 21 | print('') 22 | print(' nombr: if third argument is nombr, then grub-mbr is NOT ') 23 | print(' installed to MBR EVEN if BIOS partition is present') 24 | print('') 25 | print('Following are available disks') 26 | show_available_disks() 27 | exit(1) 28 | boot_dev = sys.argv[1] 29 | root_partition = sys.argv[2] 30 | update_mbr = True 31 | if len(sys.argv) > 3: 32 | update_mbr = (sys.argv[3] != 'nombr') 33 | 34 | d = DiskDetails(boot_dev) 35 | partnum = d.partnum_by_path(root_partition) 36 | msg = 'Confirm disk. Data will not be affected %s' % (d.devpath,) 37 | if d.confirm_action(msg, partnum): 38 | d.make_bootable(root_partition, update_mbr) 39 | update_fstab_boot_efi(boot_dev, root_partition) 40 | -------------------------------------------------------------------------------- /scripts/missing_firmware.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Run without any options or with -h | --help to see usage 4 | # If environment variable FIRMWARE_DIR is set, it uses that dir to look for 5 | # firmware - defaults to /lib/firmware 6 | 7 | FIRMWARE_DIR=${FIRMWARE_DIR:-/lib/firmware} 8 | MODULE_DIR=/lib/modules/`uname -r` 9 | 10 | 11 | function show_help() 12 | { 13 | PROG_NAME=$(basename $0) 14 | echo "Shows firmware files required but missing under /lib/firmware" 15 | echo "" 16 | echo "set FIRMWARE_DIR environment variable to check against a directory other than" 17 | echo "/lib/firmware - e.g. latest linux-firmware-git clone" 18 | echo "" 19 | echo "Usage $PROG_NAME [-h | --help | -m | -l | -a]" 20 | echo "Options:" 21 | echo " -h | --help : show usage and exit" 22 | echo "" 23 | echo " -m | --missing : Show only firmware reported as missing by running kernel" 24 | echo " Information comes from dmesg" 25 | echo "" 26 | echo " -l | --loaded : Show all firmware missing based on currently loaded modules" 27 | echo " (including builtins)" 28 | echo " This means firmware files LISTED by the modules that are currently loaded" 29 | echo " and does not necessarily mean that the module has LOADED those" 30 | echo " firmware files. Large modules like amdgpu will list MANY firmware files," 31 | echo " but will only load based on hardware detected, etc." 32 | echo "" 33 | echo " -a | --all : Show all firmware that _MAY_ be missing based on modules" 34 | echo " under /lib/modules/kernel_version" 35 | echo " Lists a LOT of firmware files:" 36 | echo " - Many relate to modules not loaded (may never be needed)" 37 | echo " - Many of these are not available under linux-firmware-git also!" 38 | echo " - These may be non-free firmware" 39 | } 40 | 41 | function check_fw() 42 | { 43 | # Reads STDIN - each line should be firmware path under FIRMWARE_DIR 44 | while read fw 45 | do 46 | if [ ! -f $FIRMWARE_DIR/$fw ]; then 47 | echo $fw 48 | fi 49 | done 50 | } 51 | 52 | function fw_loaded_modules() 53 | { 54 | for m in /sys/module/* 55 | do 56 | modinfo $(basename $(basename $m)) 2>/dev/null | perl -wnl -e '/^firmware: \s+ (\S+)/ and print $1' 57 | done 58 | } 59 | 60 | function module_list() 61 | { 62 | (cat $MODULE_DIR/modules.builtin; cut -d: -f1 < $MODULE_DIR/modules.dep) | sort | uniq 63 | } 64 | 65 | 66 | function fw_kernel_all() 67 | { 68 | module_list | while read mod_file 69 | do 70 | modinfo $MODULE_DIR/$mod_file 2>/dev/null | perl -wnl -e '/^firmware: \s+ (\S+)/ and print $1' 71 | done 72 | } 73 | 74 | function fw_kernel_missing() 75 | { 76 | dmesg | perl -wnl -e '/Direct firmware load for (\S+) failed/ and print $1' 77 | } 78 | 79 | 80 | 81 | case "$1" in 82 | -h|--help) 83 | show_help 84 | ;; 85 | -l|--loaded) 86 | fw_loaded_modules | check_fw 87 | ;; 88 | -a|--all) 89 | fw_kernel_all | check_fw 90 | ;; 91 | -m|--missing) 92 | fw_kernel_missing | check_fw 93 | ;; 94 | "") 95 | show_help 96 | ;; 97 | *) 98 | echo "Invalid option: $1" 99 | show_help 100 | exit 1 101 | ;; 102 | esac 103 | 104 | -------------------------------------------------------------------------------- /scripts/multiboot_create.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | import os # noqa: E402 5 | from common_utils import require_root_or_exit # noqa: E402 6 | from efiutils import ( 7 | DiskDetails, 8 | show_available_disks, 9 | erase_partition_table, 10 | ) # noqa: E402 11 | 12 | 13 | if __name__ == '__main__': 14 | require_root_or_exit() 15 | if len(sys.argv) < 2: 16 | print('Usage: %s dev_path' % (os.path.basename(sys.argv[0]),)) 17 | print('') 18 | print('dev_path: full path to disk (e.g. /dev/sdh}') 19 | print('') 20 | print('Following are available disks') 21 | show_available_disks() 22 | exit(1) 23 | 24 | msg = 'Confirm destroying all partitions and data on %s' % (sys.argv[1],) 25 | try: 26 | d = DiskDetails(sys.argv[1]) 27 | resp = d.confirm_action(msg) 28 | except: 29 | resp = erase_partition_table(sys.argv[1]) 30 | if not resp: 31 | exit(0) 32 | d = DiskDetails(sys.argv[1]) 33 | d.multiboot_erase_create() 34 | -------------------------------------------------------------------------------- /scripts/multiboot_install_grub.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | import os # noqa: E402 5 | from common_utils import require_root_or_exit # noqa: E402 6 | from efiutils import ( 7 | DiskDetails, 8 | show_available_disks, 9 | ) # noqa: E402 10 | 11 | 12 | if __name__ == '__main__': 13 | require_root_or_exit() 14 | if len(sys.argv) < 2: 15 | print('Usage: %s dev_path' % (os.path.basename(sys.argv[0]),)) 16 | print('') 17 | print(' dev_path: full path to disk (e.g. /dev/sdh}') 18 | print('') 19 | print('Following are available disks') 20 | show_available_disks() 21 | exit(1) 22 | d = DiskDetails(sys.argv[1]) 23 | msg = 'Confirm disk to update grub. Data will not be affected %s' % ( 24 | d.devpath,) 25 | if d.confirm_action(msg): 26 | d.multiboot_instal_grub() 27 | -------------------------------------------------------------------------------- /scripts/multiboot_update_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | import os # noqa: E402 5 | from common_utils import require_root_or_exit # noqa: E402 6 | from efiutils import ( 7 | DiskDetails, 8 | show_available_disks, 9 | ) # noqa: E402 10 | 11 | 12 | if __name__ == '__main__': 13 | require_root_or_exit() 14 | if len(sys.argv) < 2: 15 | print('Usage: %s dev_path' % (os.path.basename(sys.argv[0]),)) 16 | print('') 17 | print(' dev_path: full path to disk (e.g. /dev/sdh}') 18 | print('') 19 | print('Following are available disks') 20 | show_available_disks() 21 | exit(1) 22 | d = DiskDetails(sys.argv[1]) 23 | msg = ('Confirm disk to update grub config. ' 24 | 'Data will not be affected %s') % (d.devpath,) 25 | if d.confirm_action(msg): 26 | d.multiboot_update_config() 27 | -------------------------------------------------------------------------------- /scripts/pkgs_missing_from.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | REQD_PKGS="$*" 3 | 4 | MISSING_PKGS=$(dpkg -l $REQD_PKGS 2>/dev/null | sed -e '1,4d'| grep -v '^ii' | awk '{printf("%s ", $2)}') 5 | MISSING_PKGS="$MISSING_PKGS $(dpkg -l $REQD_PKGS 2>&1 1>/dev/null | sed -e 's/^dpkg-query: no packages found matching //')" 6 | if [ -n "${MISSING_PKGS%% }" ]; then 7 | INSTALL_CMD="sudo apt-get install $MISSING_PKGS" 8 | else 9 | INSTALL_CMD="All required packages are already installed\nRequired packages: $REQD_PKGS" 10 | fi 11 | echo $INSTALL_CMD 12 | -------------------------------------------------------------------------------- /scripts/required_pkgs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | REQD_PKGS="grub-efi-ia32-bin grub-efi-amd64-bin grub-pc-bin grub2-common grub-common util-linux parted gdisk mount xorriso genisoimage squashfs-tools rsync" 3 | 4 | $(dirname $0)/pkgs_missing_from.sh $REQD_PKGS 5 | -------------------------------------------------------------------------------- /scripts/show_1_disk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | from common_utils import require_root_or_exit # noqa: E402 5 | from efiutils import show_available_disks, DiskDetails # noqa: E402 6 | 7 | if __name__ == '__main__': 8 | require_root_or_exit() 9 | if len(sys.argv) < 2: 10 | show_available_disks() 11 | exit(0) 12 | try: 13 | d = DiskDetails(sys.argv[1]) 14 | except ValueError as e: 15 | print(e.message) 16 | exit(1) 17 | print(d) 18 | -------------------------------------------------------------------------------- /scripts/show_disks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | from common_utils import require_root_or_exit # noqa: E402 5 | from efiutils import show_available_disks # noqa: E402 6 | 7 | if __name__ == '__main__': 8 | require_root_or_exit() 9 | show_available_disks() 10 | -------------------------------------------------------------------------------- /scripts/show_disks_lsblk: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PROG_DIR=$(dirname "$BASH_SOURCE") 3 | PROG_DIR=$(readlink -e "$PROG_DIR") 4 | 5 | source "$PROG_DIR"/disk_partition_functions.sh || { 6 | >&2 echo "Could not source: $PROG_DIR/disk_partition_functions.sh" 7 | exit 1 8 | } 9 | show_disks 10 | -------------------------------------------------------------------------------- /scripts/show_iso_details.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | sys.dont_write_bytecode = True 4 | import os # noqa: E402 5 | from linuxiso import get_instance # noqa: E402 6 | 7 | if __name__ == '__main__': 8 | if len(sys.argv) < 2: 9 | print('Usage: %s &2 echo "Could not source: $PROG_DIR/disk_partition_functions.sh" 7 | exit 1 8 | } 9 | show_all_disk_partitions 10 | -------------------------------------------------------------------------------- /scripts/ubuntu_remaster_iso.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Ubuntu-specific script 3 | 4 | 5 | PROG_PATH=${PROG_PATH:-$(readlink -e $0)} 6 | PROG_DIR=$(dirname ${PROG_PATH}) 7 | PROG_NAME=$(basename ${PROG_PATH}) 8 | 9 | if [ -f "${PROG_DIR}"/remaster_iso_functions.sh ]; then 10 | source "${PROG_DIR}"/remaster_iso_functions.sh 11 | else 12 | source remaster_iso_functions.sh # current dir 13 | fi 14 | 15 | # Needs root privileges (to mount) 16 | exit_if_not_root 17 | 18 | SQUASHFS_PATH=casper/filesystem.squashfs 19 | MANIFEST_PATH=casper/filesystem.manifest 20 | SIZE_FILE=casper/filesystem.size 21 | EFI_IMG_FILE=boot/grub/efi.img 22 | 23 | # Check cmdline args 24 | function show_usage() { 25 | echo "${PROG_NAME} ISO_PATH EXTRACT_DIR OUTPUT_ISO" 26 | echo "" 27 | echo " ISO_PATH: Full path to ISO to extract" 28 | echo " EXTRACT_DIR: Dir to extract under. Will be (re-)created" 29 | echo " OUTPUT_ISO: Full path to output ISO" 30 | } 31 | 32 | if [ -z "$3" ]; then 33 | show_usage 34 | exit 1 35 | fi 36 | 37 | if [ -z "$REMASTER_CMDS_DIR" ]; then 38 | REMASTER_CMDS_DIR=${PROG_DIR}/../remaster 39 | fi 40 | if [ -d $REMASTER_CMDS_DIR ]; then 41 | REMASTER_CMDS_DIR=$(readlink -e $REMASTER_CMDS_DIR) 42 | else 43 | echo "REMASTER_CMDS_DIR not a directory: $REMASTER_CMDS_DIR" 44 | echo "Ignoring REMASTER_CMDS_DIR" 45 | REMASTER_CMDS_DIR="" 46 | fi 47 | 48 | ISO_PATH="$1" 49 | EXTRACT_DIR="$2" 50 | OUTPUT_ISO="$3" 51 | 52 | extract_iso "$ISO_PATH" "$EXTRACT_DIR" || exit 1 53 | extract_squashfs "$EXTRACT_DIR" "${ISO_EXTRACT_SUBDIR}"/"$SQUASHFS_PATH" || exit 1 54 | 55 | if [ -n "$REMASTER_CMDS_DIR" ]; then 56 | run_remaster_commands "$EXTRACT_DIR" "${REMASTER_CMDS_DIR}" 57 | else 58 | echo "No REMASTER_CMDS_DIR. Not running any remaster commands" 59 | fi 60 | 61 | update_squashfs "$EXTRACT_DIR" "$SQUASHFS_PATH" "${MANIFEST_PATH}" "${SIZE_FILE}" 62 | update_iso "$EXTRACT_DIR" "${OUTPUT_ISO}" "$ISO_PATH" "$EFI_IMG_FILE" 63 | rmdir "$EXTRACT_DIR" 64 | -------------------------------------------------------------------------------- /scripts/updated_firmware.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Run without any options or with -h | --help to see usage 4 | # MUST set If environment variable FIRMWARE_GIT_DIR - directory to compare 5 | # with /lib/firmware 6 | 7 | 8 | 9 | function show_help() 10 | { 11 | PROG_NAME=$(basename $0) 12 | echo "Lists firmware files that are new or have been updated under FIRMWARE_GIT_DIR" 13 | echo "as compared to /lib/firmware" 14 | echo "" 15 | echo "MUST set FIRMWARE_GIT_DIR - directory to compare with /lib/firmware" 16 | echo "" 17 | echo "Usage $PROG_NAME [-h | --help | -n | --new | -u | --updated" 18 | echo "Options:" 19 | echo " -h | --help : show usage and exit" 20 | echo " -n | --new : Show new firmware files" 21 | echo " -u | --updated : Show updated firmware files" 22 | } 23 | 24 | if [ -z "$1" ]; then 25 | show_help 26 | exit 0 27 | fi 28 | 29 | if [ -z "$FIRMWARE_GIT_DIR" ]; then 30 | echo "Must set FIRMWARE_GIT_DIR" 31 | exit 1 32 | fi 33 | if [ ! -d "$FIRMWARE_GIT_DIR" ]; then 34 | echo "FIRMWARE_GIT_DIR not a directory: $FIRMWARE_GIT_DIR" 35 | exit 2 36 | fi 37 | 38 | 39 | case "$1" in 40 | -h|--help) 41 | show_help 42 | ;; 43 | -u|--updated) 44 | diff -q -r /lib/firmware $FIRMWARE_GIT_DIR | perl -wnl -e '/^Files \/lib\/firmware\/(\S+) and .*? differ$/ and print $1' | egrep -v '^(.git|WHENCE|Makefile|README|copyright|check_whence.py|LICEN[SC]E.*$)' 45 | ;; 46 | -n|--new) 47 | ESCAPED_DIR=$(echo $FIRMWARE_GIT_DIR | sed -e 's/\//\\\//g') 48 | diff -q -r /lib/firmware $FIRMWARE_GIT_DIR | egrep "^Only in $FIRMWARE_GIT_DIR" | sed -e 's/^Only in //' -e 's/: /\//' -e "s/^${ESCAPED_DIR}\///" | egrep -v '^(.git|WHENCE|Makefile|README|copyright|check_whence.py|LICEN[SC]E.*$)' 49 | ;; 50 | "") 51 | show_help 52 | ;; 53 | *) 54 | echo "Invalid option: $1" 55 | show_help 56 | exit 1 57 | ;; 58 | esac 59 | 60 | --------------------------------------------------------------------------------