├── debian ├── dirs ├── source │ └── format ├── grml2usb.manpages ├── grml2usb.dirs ├── gbp.conf ├── grml2usb.install ├── tests │ ├── control │ └── smoke-grml2usb-py3 ├── rules ├── control ├── NEWS ├── copyright └── changelog ├── test ├── grml2usb.py ├── conftest.py └── grml2usb_test.py ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── check-full.yml │ ├── package-build.yml │ └── release.yml ├── mbr ├── .gitignore ├── Makefile └── mbr.S ├── pytest.ini ├── grub ├── grml.png └── splash.xpm.gz ├── doc ├── pycallgraph.png ├── Makefile └── mbr.8.adoc ├── images ├── icons │ ├── up.png │ ├── home.png │ ├── next.png │ ├── note.png │ ├── prev.png │ ├── tip.png │ ├── caution.png │ ├── example.png │ ├── warning.png │ └── important.png └── screenshot.png ├── setup.cfg ├── Makefile ├── README.md ├── zsh └── _grml2usb ├── TODO ├── grml2iso.8.adoc ├── tarball.sh ├── grml2iso ├── grml2usb.8.adoc └── grml2usb /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/sbin 2 | -------------------------------------------------------------------------------- /test/grml2usb.py: -------------------------------------------------------------------------------- 1 | ../grml2usb -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: grml 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/grml2usb.manpages: -------------------------------------------------------------------------------- 1 | grml2iso.8 2 | grml2usb.8 3 | -------------------------------------------------------------------------------- /mbr/.gitignore: -------------------------------------------------------------------------------- 1 | /mbr.o 2 | /mbrldr 3 | /mbrmgr 4 | /mbrmgr.elf 5 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | markers = 3 | check_for_usbdevice 4 | -------------------------------------------------------------------------------- /debian/grml2usb.dirs: -------------------------------------------------------------------------------- 1 | usr/share/grml2usb/grub 2 | usr/share/grml2usb/mbr 3 | -------------------------------------------------------------------------------- /grub/grml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/grub/grml.png -------------------------------------------------------------------------------- /doc/pycallgraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/doc/pycallgraph.png -------------------------------------------------------------------------------- /grub/splash.xpm.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/grub/splash.xpm.gz -------------------------------------------------------------------------------- /images/icons/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/up.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E203, E501, W503 3 | filename = ./grml2usb, *.py 4 | -------------------------------------------------------------------------------- /images/icons/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/home.png -------------------------------------------------------------------------------- /images/icons/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/next.png -------------------------------------------------------------------------------- /images/icons/note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/note.png -------------------------------------------------------------------------------- /images/icons/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/prev.png -------------------------------------------------------------------------------- /images/icons/tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/tip.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/screenshot.png -------------------------------------------------------------------------------- /images/icons/caution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/caution.png -------------------------------------------------------------------------------- /images/icons/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/example.png -------------------------------------------------------------------------------- /images/icons/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/warning.png -------------------------------------------------------------------------------- /images/icons/important.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grml/grml2usb/HEAD/images/icons/important.png -------------------------------------------------------------------------------- /debian/gbp.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | debian-tag = v%(version)s 3 | 4 | # Options only affecting "gbp dch" 5 | [dch] 6 | id-length = 7 7 | meta = True 8 | multimaint-merge = True 9 | -------------------------------------------------------------------------------- /debian/grml2usb.install: -------------------------------------------------------------------------------- 1 | grml2iso usr/sbin/ 2 | grml2usb usr/sbin/ 3 | grub/ usr/share/grml2usb/ 4 | mbr/mbrldr usr/share/grml2usb/mbr/ 5 | mbr/mbrmgr usr/share/grml2usb/mbr/ 6 | -------------------------------------------------------------------------------- /debian/tests/control: -------------------------------------------------------------------------------- 1 | Tests: smoke-grml2usb-py3 2 | Depends: 3 | dosfstools, 4 | isolinux, 5 | kpartx, 6 | python3, 7 | syslinux, 8 | syslinux-common, 9 | xorriso, 10 | @, 11 | Restrictions: needs-root, isolation-machine, breaks-testbed 12 | -------------------------------------------------------------------------------- /mbr/Makefile: -------------------------------------------------------------------------------- 1 | # https://www.mirbsd.org/cvs.cgi/~checkout~/src/sys/arch/i386/stand/mbr/mbr.S 2 | 3 | all: mbrmgr mbrldr 4 | 5 | clean: 6 | rm -f mbrmgr mbrldr 7 | 8 | mbrmgr: 9 | nasm -D__BOOT_VER=\"0AA6\" -DBOOTMANAGER mbr.S -o mbrmgr 10 | 11 | # bootloader, without a bootmenu 12 | mbrldr: 13 | $ nasm -D__BOOT_VER=\"0AA6\" -DBOOT_QUIET mbr.S -o mbrldr 14 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | day: "monday" 9 | time: "08:00" 10 | open-pull-requests-limit: 5 11 | commit-message: 12 | prefix: "ci" 13 | include: "scope" 14 | -------------------------------------------------------------------------------- /test/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | 5 | 6 | def pytest_configure(config): 7 | config.addinivalue_line("markers", "require_root: mark test to run only as root") 8 | 9 | 10 | def pytest_runtest_setup(item): 11 | if "require_root" in {mark.name for mark in item.iter_markers()}: 12 | if os.getuid() != 0: 13 | pytest.skip("must be root") 14 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # Uncomment this to turn on verbose mode. 4 | #export DH_VERBOSE=1 5 | 6 | VERSION:=$(shell dpkg-parsechangelog | awk '/Version: / { print $$2 }') 7 | 8 | %: 9 | dh $@ 10 | 11 | override_dh_auto_build: 12 | dh_testdir 13 | grep -qE '^PROG_VERSION = "\*\*\*UNKNOWN\*\*\*"' grml2usb || (echo "PROG_VERSION in grml2usb wrong." && exit 2) 14 | $(MAKE) -C mbr 15 | $(MAKE) doc 16 | 17 | override_dh_fixperms: 18 | chmod 664 ./debian/grml2usb/usr/share/grml2usb/mbr/mbrldr 19 | chmod 664 ./debian/grml2usb/usr/share/grml2usb/mbr/mbrmgr 20 | dh_fixperms 21 | 22 | override_dh_install: 23 | dh_install 24 | sed -i -e "s/^PROG_VERSION = \"\*\*\*UNKNOWN\*\*\*\"/PROG_VERSION = \"$(VERSION)\"/" ./debian/grml2usb/usr/sbin/grml2usb 25 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | all: doc 2 | 3 | doc: doc_man doc_html 4 | 5 | doc_html: html-stamp 6 | 7 | html-stamp: mbr.8.adoc 8 | asciidoc -b xhtml11 -a icons mbr.8.adoc 9 | touch html-stamp 10 | 11 | doc_man: man-stamp 12 | 13 | man-stamp: mbr.8.adoc 14 | asciidoc -d manpage -b docbook mbr.8.adoc 15 | sed -i 's///' mbr.8.xml 16 | xsltproc --novalid --nonet /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl mbr.8.xml 17 | # ugly hack to avoid duplicate empty lines in manpage 18 | # notice: docbook-xsl 1.71.0.dfsg.1-1 is broken! make sure you use 1.68.1.dfsg.1-0.2! 19 | cp mbr.8 mbr.8.tmp 20 | uniq mbr.8.tmp > mbr.8 21 | # ugly hack to avoid '.sp' at the end of a sentence or paragraph: 22 | sed -i 's/\.sp//' mbr.8 23 | rm mbr.8.tmp 24 | touch man-stamp 25 | 26 | clean: 27 | rm -rf mbr.8.html mbr.8.xml mbr.8 html-stamp man-stamp 28 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: grml2usb 2 | Section: admin 3 | Priority: optional 4 | Maintainer: Grml Team 5 | Uploaders: 6 | Michael Prokop , 7 | Alexander Wirt , 8 | Chris Hofstaedtler , 9 | Ulrich Dangel , 10 | Build-Depends: 11 | asciidoc, 12 | debhelper-compat (= 12), 13 | docbook-xsl, 14 | nasm, 15 | xsltproc, 16 | Standards-Version: 4.6.2 17 | Rules-Requires-Root: no 18 | Homepage: https://grml.org/grml2usb/ 19 | Vcs-Git: https://github.com/grml/grml2usb.git 20 | Vcs-Browser: https://github.com/grml/grml2usb 21 | 22 | Package: grml2usb 23 | Architecture: all 24 | Depends: 25 | kmod, 26 | mtools, 27 | python3, 28 | python3-parted, 29 | rsync, 30 | syslinux | grub-efi-amd64-signed | grub-pc-bin | grub-efi-arm64-bin | grub-common, 31 | syslinux | grub-common, 32 | ${misc:Depends}, 33 | ${shlibs:Depends}, 34 | Recommends: 35 | isolinux (>= 3:6.03+dfsg-5+deb8u1~), 36 | syslinux, 37 | syslinux-utils, 38 | xorriso | genisoimage, 39 | Description: install Grml system / ISO to USB device 40 | This script installs a Grml ISO to an USB device to be able 41 | to boot from it. Make sure you have at least one Grml ISO 42 | or a running Grml system (/run/live/medium) available. 43 | -------------------------------------------------------------------------------- /.github/workflows/check-full.yml: -------------------------------------------------------------------------------- 1 | name: Code Testing 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | push: 6 | schedule: 7 | - cron: '42 1 * * *' 8 | 9 | concurrency: 10 | group: "codecheck-${{ github.ref }}" 11 | cancel-in-progress: true 12 | jobs: 13 | codecheck: 14 | runs-on: ubuntu-latest 15 | name: Run codecheck 16 | 17 | steps: 18 | - name: Checkout source 19 | uses: actions/checkout@v6 20 | 21 | - name: pip install wheel (to make install black work) 22 | run: pip3 install wheel 23 | 24 | - name: pip install flake8, isort + black, vulture 25 | run: pip3 install flake8 isort black vulture 26 | 27 | - name: Codecheck execution 28 | run: make codecheck 29 | 30 | unittests: 31 | runs-on: ubuntu-latest 32 | name: Run unit tests as root 33 | 34 | steps: 35 | - name: Checkout source 36 | uses: actions/checkout@v6 37 | 38 | - name: Install pytest and deps 39 | run: sudo apt install python3-pytest python3-parted syslinux grub-efi-amd64-signed grub2-common parted curl nasm make 40 | 41 | - name: Compile mbr 42 | run: make -C mbr 43 | 44 | # tests need root, as they manage loopdevs etc. 45 | - name: Run Pytest 46 | run: sudo pytest-3 47 | -------------------------------------------------------------------------------- /debian/tests/smoke-grml2usb-py3: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec 2>&1 3 | set -ex 4 | 5 | TMPDIR=$(mktemp -d) 6 | LODEV=$(losetup -f) 7 | cleanup() { 8 | kpartx -d "$LODEV" || true 9 | losetup -d "$LODEV" || true 10 | rm -rf "$TMPDIR" 11 | } 12 | trap cleanup EXIT 13 | 14 | mkdir "$TMPDIR"/isoroot "$TMPDIR"/isoroot/boot "$TMPDIR"/isoroot/boot/isolinux 15 | cp /usr/lib/ISOLINUX/isolinux.bin "$TMPDIR"/isoroot/boot/isolinux/ 16 | echo 'FAKE' > "$TMPDIR"/isoroot/grml-version 17 | echo 'LOGO' > "$TMPDIR"/isoroot/boot/logo.16 18 | touch "$TMPDIR"/isoroot/boot/isolinux/FAKE_default.cfg 19 | touch "$TMPDIR"/isoroot/boot/isolinux/FAKE_grml.cfg 20 | touch "$TMPDIR"/isoroot/boot/isolinux/hidden.cfg 21 | xorriso -as mkisofs -l -r -J -no-pad -no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat -o "$TMPDIR"/fake.iso "$TMPDIR"/isoroot 22 | xorriso -dev "$TMPDIR"/fake.iso -ls 23 | 24 | dd if=/dev/zero of="$TMPDIR"/blockdev bs=1M count=50 25 | 26 | sfdisk "$TMPDIR"/blockdev < Mon, 3 Oct 2011 22:56:35 +0200 11 | 12 | grml2usb (0.9.13) unstable; urgency=low 13 | 14 | This release makes syslinux the default bootloader again. 15 | Grub fails just too often. Therefore the --syslinux options 16 | is deprecated and option --grub was introduced instead. 17 | 18 | This release provides decent support for multi-ISO within the 19 | new vesamenu bootsplash, providing a menu based system. We had 20 | to break backward compatibility (otherwise the isolinux/syslinux 21 | code would be unmaintainable). Therefore support for older ISOs 22 | (everything before grml release 2009.10) had to be dropped. If 23 | you still need an old version of Grml on your usb device just 24 | use an older version of grml2usb (the old grml2usb versions 25 | support recent ISOs too, they just don't use/support the new 26 | vesamenu bootsplash then). The grml team supports old 27 | grml2usb versions through the grml2usb-compat script. 28 | Further details are available in the FAQ at 29 | http://grml.org/grml2usb/#grml2usb-compat 30 | 31 | -- Michael Prokop Wed, 21 Oct 2009 23:32:08 +0200 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grml2usb 2 | 3 | [![Sponsor](https://img.shields.io/badge/Sponsor-GitHub-purple?logo=github)](https://github.com/sponsors/grml) 4 | [![GitHub release](https://img.shields.io/github/v/release/grml/grml2usb)](https://github.com/grml/grml2usb/releases) 5 | [![Debian package](https://img.shields.io/debian/v/grml2usb/trixie?label=debian)](https://packages.debian.org/trixie/grml2usb) 6 | [![Ubuntu package](https://img.shields.io/ubuntu/v/grml2usb)](https://packages.ubuntu.com/search?keywords=grml2usb) 7 | 8 | Install [Grml](https://grml.org/) Live Linux to a USB key drive. 9 | 10 | ## Purpose 11 | 12 | This tool installs a Grml ISO image (or a running Grml) to USB drives, making them bootable. 13 | You can install multiple Grml flavours on the same USB drive, for example both `amd64` and `arm64` versions. 14 | 15 | ## Installation 16 | 17 | ### From Debian repositories 18 | 19 | ```bash 20 | sudo apt install grml2usb 21 | ``` 22 | 23 | ### From GitHub releases 24 | 25 | Download the latest release from [GitHub Releases](https://github.com/grml/grml2usb/releases), and then: 26 | 27 | ```bash 28 | # Download and install .deb package 29 | sudo apt install ./grml2usb_*.deb 30 | ``` 31 | 32 | ## Quick Start 33 | 34 | 1. Install `grml2usb` package 35 | 2. [Download a Grml ISO image](https://grml.org/download/) 36 | 3. Install it to USB device: 37 | ```bash 38 | sudo grml2usb grml.iso /dev/sdX1 39 | ``` 40 | 41 | **Warning:** Replace `/dev/sdX1` with the FAT partition on your USB device. 42 | This will destroy all data on the device. 43 | 44 | ## Documentation 45 | 46 | For detailed usage instructions and all available options, visit: https://grml.org/grml2usb/ 47 | 48 | ## License 49 | 50 | This project is licensed under the GPL v2+. 51 | 52 | ## Contributing 53 | 54 | - **Source code**: https://github.com/grml/grml2usb 55 | - **Issues**: https://github.com/grml/grml2usb/issues 56 | - **Releases**: https://github.com/grml/grml2usb/releases 57 | - **Grml Live Linux**: https://grml.org 58 | -------------------------------------------------------------------------------- /zsh/_grml2usb: -------------------------------------------------------------------------------- 1 | #compdef grml2usb 2 | # Filename: /etc/zsh/completion.d/_grml2usb 3 | # Purpose: completion of command grml2usb for zsh (z shell) 4 | # Authors: grml-team (grml.org), (c) Michael Prokop 5 | # Bug-Reports: see http://grml.org/bugs/ 6 | # License: This file is licensed under the GPL v2. 7 | ################################################################################ 8 | 9 | local arguments dev 10 | local -a devices 11 | 12 | devices=() 13 | 14 | for dev in /dev/sd* /dev/hd* ; do 15 | if [[ $(cat /sys/block/${dev#*dev/}/removable 2>/dev/null) == '1' ]] ; then 16 | part=$(ls /dev/${dev#*dev/}[0-9]) 17 | devices+=$part 18 | fi 19 | done 20 | 21 | # TODO: 22 | # * handling of --bootoptions=BOOTOPTIONS 23 | # * $devices should also list directories as valid target 24 | # * as output before :device:.... ISO files and/or /run/live/medium should be suggested 25 | 26 | arguments=( 27 | '--help[display help message and exit]:' 28 | '--bootoptions=[use specified bootoptions as default]:' 29 | '--bootloader-only[do not copy files but just install a bootloader]' 30 | '--copy-only[copy files only but do not install bootloader]' 31 | '--dry-run[avoid executing commands]' 32 | '--format[format specified partition with FAT]' 33 | '--force[force any actions requiring manual interaction]' 34 | '--mbr-manager[enable interactive boot manager menu in MBR]' 35 | '--quiet[do not output anything but just errors on console]' 36 | '--skip-addons[do not install /boot/addons/ files]' 37 | '--skip-mbr[do not install a master boot record (MBR) on the device]' 38 | '--syslinux[install syslinux bootloader instead of grub]' 39 | '--syslinux-mbr[install syslinux master boot record (MBR) instead of default]' 40 | '--verbose[enable verbose mode]' 41 | '--version[display program version and exit]' 42 | ':device:($devices)' 43 | ) 44 | _arguments -s $arguments 45 | 46 | ## END OF FILE ################################################################# 47 | # vim:foldmethod=marker 48 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | TODOs 2 | ----- 3 | 4 | * if 'grml2usb grml64.iso grml.iso' is invoked there are two identically named boot entries (both "grml") 5 | * support installation of new ISO[s] additionally to already existing grml ISOs on the usb device 6 | -> add "old"/already existing images automatically to bootloader configuration [thx gebi] 7 | * support installation of "dupes", meaning grml2usb grml_2008.11.iso grml_2009.05.iso 8 | * write bootloader configuration snippets to boot/releases//{grub.cfg,syslinux.cfg,...} 9 | -> this could simplify live dramatically especially when supporting "already existing" images [thx gebi] 10 | * support integration of Debian ISOs (like netboot) 11 | * provide simple output being between default and --quiet [thx gebi], like: 12 | # grml2usb iso1 iso2 /dev/sda1 13 | installing: 14 | iso1.... OK 15 | iso2.... FAIL (error) 16 | done. 17 | * provide default entry of all installed ISOs on the top of the bootscreen 18 | - done for isolinux 19 | - missing in grub 20 | * implement --kernel option to install specific linux26 file 21 | * implement --initrd option to install specific initrd file 22 | * implement --squashfs option to install specific squashfs file 23 | * implement --verify option to check md5sums/sha1sums of files on usb device 24 | * implement --uninstall option to remove all grml2usb files in a clean manner 25 | -> implement logic for storing information about copied files (register every file in a set()) 26 | * implement --create-partition[s] option to generate a default partition setup 27 | * implement --validate option to validate partition schema/layout: is the partition schema ok and the bootable flag set? 28 | * the last line in bootsplash (boot.msg) of syslinux should mention all installed grml flavours 29 | (attention, the line should NOT become too long :)) 30 | * code improvements: 31 | - use 'with open("...", "w") as f: ... f.write("...")' 32 | - use class design (like used in https://fedorahosted.org/liveusb-creator/browser/liveusb) 33 | * provide a Windows version (for example via PyQt4) 34 | * provide unit-testing (any ideas for useful/test-able scenarious?) 35 | * provide progress bar when copying files 36 | * provide graphical version; any volunteers? :) 37 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Michael Prokop on 2 | Sun, 14 Aug 2005 15:31:04 +0200. 3 | 4 | It was downloaded from http://grml.org/ 5 | 6 | Upstream Author: Michael Prokop 7 | 8 | Copyright: 9 | 10 | grml2usb: 11 | 12 | This software is Copyright (c) 2006-2019 by Michael Prokop and 13 | others. 14 | 15 | This package is free software; you can redistribute it and/or modify 16 | it under the terms of the GNU General Public License as published by 17 | the Free Software Foundation; version 2 dated June, 1991. 18 | 19 | This package is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License 25 | along with this package; if not, see /usr/share/common-licenses/GPL-2. 26 | 27 | 28 | grub/splash.xpm.gz and grub/grml.png: 29 | 30 | Copyright by Martin Ahammer / grml-team 31 | 32 | 33 | images/icons/: 34 | 35 | Copyright 2008 by Stuart Rackham 36 | (Taken from AsciiDoc.) 37 | AsciiDoc is free software and is licenced under the terms of the 38 | GNU General Public License version 2. 39 | 40 | 41 | mbr/mbr.S: 42 | 43 | Copyright (c) 2009 Thorsten Glaser 44 | Provided that these terms and disclaimer and all copyright notices 45 | are retained or reproduced in an accompanying document, permission 46 | is granted to deal in this work without restriction, including un- 47 | limited rights to use, publicly perform, distribute, sell, modify, 48 | merge, give away, or sublicence. 49 | 50 | This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 51 | the utmost extent permitted by applicable law, neither express nor 52 | implied; without malicious intent or gross negligence. In no event 53 | may a licensor, author or contributor be held liable for indirect, 54 | direct, other damage, loss, or other issues arising in any way out 55 | of dealing in the work, even if advised of the possibility of such 56 | damage or existence of a defect, except proven that it results out 57 | of said person's immediate fault when using the work as intended. 58 | 59 | 60 | On Debian GNU/Linux systems, the complete text of the GNU General 61 | Public License can be found in `/usr/share/common-licenses/GPL-2'. 62 | -------------------------------------------------------------------------------- /.github/workflows/package-build.yml: -------------------------------------------------------------------------------- 1 | name: package-build 2 | on: 3 | pull_request: 4 | push: 5 | tags: 6 | - 'v*' 7 | permissions: 8 | actions: read 9 | contents: read 10 | pull-requests: write 11 | concurrency: 12 | group: "${{ github.ref }}" 13 | cancel-in-progress: true 14 | jobs: 15 | build-debian: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v6 19 | - name: "Update changelog" 20 | run: | 21 | set -ex 22 | OLD_VERSION=$(dpkg-parsechangelog -SVersion) 23 | SOURCE=$(dpkg-parsechangelog -SSource) 24 | if [[ "${{ github.ref_type }}" == "tag" ]]; then 25 | VERSION_SUFFIX="+gh" 26 | else 27 | VERSION_SUFFIX="+autobuild${GITHUB_RUN_NUMBER}" 28 | fi 29 | cat > debian/changelog < $(date -R) 35 | EOT 36 | - uses: jtdor/build-deb-action@v1 37 | - name: Archive build result 38 | uses: actions/upload-artifact@v6 39 | with: 40 | name: packages 41 | if-no-files-found: error 42 | retention-days: 14 43 | path: | 44 | debian/artifacts/*.deb 45 | debian/artifacts/*.tar.* 46 | - name: Comment PR with artifact link 47 | if: github.event_name == 'pull_request' 48 | uses: actions/github-script@v8 49 | with: 50 | script: | 51 | const runId = context.runId; 52 | const repoOwner = context.repo.owner; 53 | const repoName = context.repo.repo; 54 | 55 | // Get the artifact download URL 56 | const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ 57 | owner: repoOwner, 58 | repo: repoName, 59 | run_id: runId 60 | }); 61 | 62 | const packagesArtifact = artifacts.data.artifacts.find(artifact => artifact.name === 'packages'); 63 | if (!packagesArtifact) { 64 | console.log('No packages artifact found'); 65 | return; 66 | } 67 | 68 | const artifactUrl = `https://github.com/${repoOwner}/${repoName}/actions/runs/${runId}/artifacts/${packagesArtifact.id}`; 69 | 70 | github.rest.issues.createComment({ 71 | issue_number: context.issue.number, 72 | owner: context.repo.owner, 73 | repo: context.repo.repo, 74 | body: `📦 Built packages are ready! [Download here](${artifactUrl}).` 75 | }); 76 | -------------------------------------------------------------------------------- /test/grml2usb_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | grml2usb basic pytests 3 | ~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | This script contains basic "unit" tests, implemented for and executed with pytest. 6 | 7 | Requirements: 8 | pytest (pip install pytest) 9 | 10 | Runwith: 11 | $ pytest [-m {basic}] 12 | 13 | :copyright: (c) 2020 by Manuel Rom 14 | :license: GPL v2 or any later version 15 | :bugreports: http://grml.org/bugs/ 16 | """ 17 | 18 | import argparse 19 | import importlib 20 | import os 21 | import subprocess 22 | 23 | import pytest 24 | 25 | grml2usb = importlib.import_module("grml2usb", ".") 26 | 27 | 28 | @pytest.mark.check_for_usbdevice 29 | def test_extract_device_name(): 30 | """Assert, that 'extract_device_name' returns a device name for a given path""" 31 | assert grml2usb.extract_device_name("/dev/sda") == "sda" 32 | assert grml2usb.extract_device_name("/dev/sdb") == "sdb" 33 | assert grml2usb.extract_device_name("/dev/sdb4") == "sdb" 34 | 35 | 36 | @pytest.mark.check_for_usbdevice 37 | def test_extract_device_name_invalid(): 38 | """Assert, that 'extract_device_name' raises an Error, when given an incorrect string""" 39 | with pytest.raises(AttributeError): 40 | assert grml2usb.extract_device_name("/dev") 41 | with pytest.raises(AttributeError): 42 | assert grml2usb.extract_device_name("foobar") 43 | 44 | 45 | def _run_x(args, check: bool = True, **kwargs): 46 | # str-ify Paths, not necessary, but for readability in logs. 47 | args = [arg if isinstance(arg, str) else str(arg) for arg in args] 48 | args_str = '" "'.join(args) 49 | print(f'D: Running "{args_str}"', flush=True) 50 | return subprocess.run(args, check=check, **kwargs) 51 | 52 | 53 | def _find_free_loopdev() -> str: 54 | return _run_x(["losetup", "-f"], capture_output=True).stdout.decode().strip() 55 | 56 | 57 | def _identify_file(path) -> str: 58 | return _run_x(["file", path], capture_output=True).stdout.decode().strip().split(": ", 1)[1] 59 | 60 | 61 | @pytest.mark.require_root 62 | def test_smoke(tmp_path): 63 | loop_dev = _find_free_loopdev() 64 | partition = f"{loop_dev!s}p1" 65 | 66 | iso_url = "https://daily.grml.org/grml-small-amd64-unstable/latest/grml-small-amd64-unstable_latest.iso" 67 | iso_name = "grml.iso" 68 | if not os.path.exists(iso_name): 69 | _run_x(["curl", "-fSl#", "--output", iso_name, iso_url]) 70 | 71 | grml2usb_options = grml2usb.parser.parse_args(["--format", "--force", iso_name, partition]) 72 | print("Options:", grml2usb_options) 73 | 74 | part_size = 1 * 1024 * 1024 # 1 GB 75 | part_size_sectors = int(part_size * (1024 / 512)) 76 | dd_size = str(int((part_size / 1024) + 100)) 77 | 78 | # format (see sfdisk manual page): 79 | # ,,, 80 | # 1st partition, EFI (FAT-12/16/32, ID ef) + bootable flag 81 | sfdisk_template = f"2048,{part_size_sectors},ef,*\n" 82 | print("Using sfdisk template:\n", sfdisk_template, "\n---") 83 | loop_backing_file = tmp_path / "loop" 84 | 85 | _run_x(["dd", "if=/dev/zero", f"of={loop_backing_file!s}", "bs=1M", f"count={dd_size}"]) 86 | sfdisk_input_file = tmp_path / "sfdisk.txt" 87 | with sfdisk_input_file.open("wt") as fh: 88 | fh.write(sfdisk_template) 89 | fh.flush() 90 | 91 | with sfdisk_input_file.open() as fh: 92 | _run_x(["/sbin/sfdisk", loop_backing_file], stdin=fh) 93 | 94 | _run_x(["losetup", loop_dev, loop_backing_file]) 95 | _run_x(["partprobe", loop_dev]) 96 | 97 | try: 98 | grml2usb.main(grml2usb_options) 99 | finally: 100 | _run_x(["losetup", "-d", loop_dev]) 101 | 102 | assert _identify_file(loop_backing_file).startswith("DOS/MBR boot sector; partition 1 : ID=0xef, active") 103 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | 7 | jobs: 8 | create-release: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | actions: read 12 | contents: write 13 | steps: 14 | - uses: actions/checkout@v6 15 | 16 | - name: Extract version from tag 17 | id: version 18 | run: | 19 | TAG_NAME="${GITHUB_REF#refs/tags/}" 20 | VERSION="${TAG_NAME#v}" 21 | echo "version=${VERSION}" >> "$GITHUB_OUTPUT" 22 | echo "tag=${TAG_NAME}" >> "$GITHUB_OUTPUT" 23 | 24 | - name: Extract changelog entry 25 | id: changelog 26 | run: | 27 | VERSION="${{ steps.version.outputs.version }}" 28 | 29 | # Extract and clean changelog for this specific version 30 | CHANGES=$(dpkg-parsechangelog -l debian/changelog --since "${VERSION}" --until "${VERSION}" --show-field Changes | \ 31 | sed '/^[a-zA-Z0-9-].*([^)]*)[[:space:]]*.*$/d' | \ 32 | sed 's/^[[:space:]]*\.[[:space:]]*$//' | \ 33 | sed '/^[[:space:]]*$/d' | \ 34 | sed 's/^[[:space:]]*\*[[:space:]]*/- /' | \ 35 | sed 's/^[[:space:]]*\\+[[:space:]]*/ - /') 36 | 37 | # Set as output for use in release 38 | { 39 | echo 'description<> "$GITHUB_OUTPUT" 43 | 44 | - name: Wait for and get package build run ID 45 | id: build-run 46 | uses: actions/github-script@v8 47 | with: 48 | script: | 49 | const maxWaitTime = 10 * 60 * 1000; // 10 minutes 50 | const pollInterval = 30 * 1000; // 30 seconds 51 | const startTime = Date.now(); 52 | 53 | while (Date.now() - startTime < maxWaitTime) { 54 | const runs = await github.rest.actions.listWorkflowRuns({ 55 | owner: context.repo.owner, 56 | repo: context.repo.repo, 57 | workflow_id: 'package-build.yml', 58 | head_sha: context.sha, 59 | status: 'completed', 60 | conclusion: 'success' 61 | }); 62 | 63 | if (runs.data.workflow_runs.length > 0) { 64 | const runId = runs.data.workflow_runs[0].id; 65 | console.log(`Found successful package-build run: ${runId}`); 66 | return runId; 67 | } 68 | 69 | console.log('Package-build workflow not completed yet, waiting...'); 70 | await new Promise(resolve => setTimeout(resolve, pollInterval)); 71 | } 72 | 73 | throw new Error('Package-build workflow did not complete successfully within 10 minutes'); 74 | 75 | - name: Download build artifacts 76 | uses: actions/download-artifact@v7 77 | with: 78 | name: packages 79 | path: artifacts/ 80 | run-id: ${{ steps.build-run.outputs.result }} 81 | github-token: ${{ secrets.GITHUB_TOKEN }} 82 | 83 | - name: Create GitHub Release 84 | run: | 85 | DEB_FILE=$(find artifacts -name "*.deb" -printf "%f\n" | head -1) 86 | gh release create "${{ steps.version.outputs.tag }}" \ 87 | --title "Release ${{ steps.version.outputs.tag }}" \ 88 | --notes "## Changes in ${{ steps.version.outputs.version }} 89 | 90 | ${{ steps.changelog.outputs.description }} 91 | 92 | --- 93 | 94 | 📦 **Installation:** 95 | Download the package and install with: 96 | \`\`\`bash 97 | sudo apt install ./${DEB_FILE} 98 | \`\`\`" \ 99 | artifacts/* 100 | env: 101 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 102 | -------------------------------------------------------------------------------- /doc/mbr.8.adoc: -------------------------------------------------------------------------------- 1 | Master Boot Record, Booting from USB etc.(8) 2 | ============================================ 3 | 4 | Name 5 | ---- 6 | mbr - Master Boot Record, Booting from USB etc. 7 | 8 | Synopsis 9 | -------- 10 | 11 | None. :) 12 | 13 | [IMPORTANT] 14 | This document is work in progress. 15 | 16 | [NOTE] 17 | We are using /dev/sdz as the typical device name. Adjust it to whatever 18 | your device corresponds to of course, it's just to prevent any data loss due to 19 | wrong copy/paste. 20 | 21 | Layout 22 | ------ 23 | 24 | The Master Boot Record (MBR) is the first data block with 512 bytes on the x86 25 | architecture providing a partition table and a bootloader. In the first 446 26 | bytes is the bootcode, providing the bootloader (400 bytes), a disk signature (4 27 | bytes) and NULL (2 bytes). The following 64 bytes are the partition table, 28 | followed by 2 bytes which are the MBR signature. 29 | 30 | Bootcode 31 | ~~~~~~~~ 32 | 33 | The bootcode consists of bootloader and disk signature: 34 | 35 | Bootloader 36 | ^^^^^^^^^^ 37 | 38 | Windows: ntldr with boot.ini (Windows NT/XP) or bootmgr with \Boot\BCD (Windows Vista) 39 | 40 | Disk Signature 41 | ^^^^^^^^^^^^^^ 42 | 43 | Operating systems like Windows identify the disk using the disk signature. 44 | Running 'fixmbr' doesn't touch the disk signature but just the bootloader. 45 | Running 'fdisk /mbr' touches the bootloader *and* the disk signature (it writes 46 | a standard MBR, it won't touch the partition table though). 47 | TODO: what about fixboot? 48 | 49 | Partition table 50 | ~~~~~~~~~~~~~~~ 51 | 52 | Harddisk addressable: 8GB (Cylinder Head Sector, CHS), 2TB (Logical Block 53 | Addressing with 32bit, LBA) or >2TB (GUID Partition Table, GPT) 54 | 55 | MBR Signature 56 | ~~~~~~~~~~~~~ 57 | 58 | The 2 bytes 55 and AA (both hex), known as the Magic Number. This signature 59 | tells the system that there should exist a valid MBR - otherwise you'll get 60 | something like "No operating system" or "Non-Bootable Disk". 61 | 62 | Backup and Restore 63 | ------------------ 64 | 65 | Clone whole MBR: 66 | 67 | # dd if=/dev/sdz of=mbr_backup.dd bs=512 count=1 68 | 69 | Restore the MBR again: 70 | 71 | # dd if=mbr_backup.dd of=/dev/sdz bs=512 count=1 72 | 73 | Clone MBR *without* partition table: 74 | 75 | # dd if=/dev/sdz of=mbr_bootcode.dd bs=446 count=1 76 | 77 | Restore MBR *without* partition table again: 78 | 79 | # dd if=mbr_bootcode.dd of=/dev/sdz bs=446 count=1 80 | 81 | Backup partition layout: 82 | 83 | # sfdisk -d /dev/sdz > backup.sfdisk 84 | 85 | Restore partition layout again: 86 | 87 | # sfdisk /dev/sdz < backup.sfdisk 88 | 89 | Write new, clean MBR: 90 | 91 | lilo -M /dev/sdz -s /dev/null 92 | 93 | USB modes 94 | --------- 95 | 96 | * USB-HDD: usually the default and preferred booting mode. 97 | * USB-ZIP: ??? - can be set up via: 98 | 99 | # mkdiskimage -4 /dev/sdz 1 64 32 # device = 1GB 100 | # mkdiskimage -4 /dev/sdz 0 128 32 # device >1GB and <=2GB 101 | # mkdiskimage -F -4 /dev/sdz 0 255 63 # device >2GB and <=8GB 102 | 103 | For devices above 8GB (taken from 104 | http://www.knoppix.net/wiki/Bootable_USB_Key): 105 | 106 | # mkdiskimage -F -4 /dev/sdz 1 255 63 107 | # dd if=/dev/zero of=/dev/sdz bs=1 seek=446 count=64 108 | # echo -e ',0\n,0\n,0\n,,C,*' | sfdisk /dev/sdz 109 | 110 | USB-ZIP requires to have 64 heads and 32 sectors and less than 1024 111 | cylinder count. 112 | 113 | * USB-Floppy: ??? 114 | 115 | TODO 116 | ---- 117 | 118 | Check out the *real* difference between: 119 | 120 | # mbr-install /dev/ice 121 | # lilo -S /dev/null -M /dev/ice ext && lilo -S /dev/null -A /dev/ice 1 122 | # cat /usr/lib/syslinux/mbr.bin > /dev/ice 123 | # syslinux /dev/iceX 124 | # syslinux -sf /dev/iceX 125 | # mkdiskimage ... (USB-ZIP?) 126 | # ...? 127 | 128 | Partition stuff: 129 | 130 | * How does a correct partition look like? 131 | * The partition should start behind MBR at 1st cylinder and 63rd sector? 132 | * fdisk -l -u /dev/sdz vs. fdisk -l /dev/sdz 133 | 134 | Resources 135 | --------- 136 | 137 | * http://de.wikipedia.org/wiki/Master_Boot_Record 138 | * http://en.wikipedia.org/wiki/Master_boot_record 139 | * http://michael-prokop.at/blog/2007/04/22/booting-from-usb-pen-troubleshooting-and-pitfalls/ 140 | * http://www.ata-atapi.com/hiwmbr.html 141 | * http://thestarman.pcministry.com/asm/mbr/index.html 142 | -------------------------------------------------------------------------------- /grml2iso.8.adoc: -------------------------------------------------------------------------------- 1 | grml2iso(8) 2 | =========== 3 | 4 | Name 5 | ---- 6 | grml2iso - create a multiboot Grml ISO using grml2usb 7 | 8 | Synopsis 9 | -------- 10 | grml2iso -o 11 | 12 | ******************************************************************************* 13 | Important! The Grml team does not take responsibility for loss of any data! 14 | ******************************************************************************* 15 | 16 | Introduction 17 | ------------ 18 | 19 | grml2iso allows you to create a multiboot Grml ISO. 20 | You can specify two or more Grml ISOs and will get one single multiboot ISO as a result. 21 | grml2iso requires and uses grml2usb for this task. 22 | 23 | Important 24 | --------- 25 | 26 | The order of the provided ISOs matters for two reasons: 27 | 28 | 1) order in boot menu entries: the first ISO specified is listed as first (default) option in the boot menu, further ISOs will be listed below as next options 29 | 30 | 2) EFI image to be used: the EFI image for booting via (U)EFI will be taken from the last provided ISO. 31 | Therefore to be able to boot on 64bit EFI systems, you need to provide a 64bit ISO (like grml64-small or grml64-full) as _last_ ISO in the grml2iso command line. 32 | 33 | Options 34 | ------- 35 | 36 | grml2iso supports the environment variables GRML2USB and WRKDIR. 37 | GRML2USB specifies the path to the grml2usb script you'd like to use. 38 | WRKDIR specifies the work directory for creating the filesystem. 39 | The work directory needs at least as much free disk space as the sum of all specified ISOs. 40 | 41 | *-o *:: 42 | 43 | This option is mandatory and specifies where the resulting multiboot Grml ISO should be placed. 44 | Note that (to avoid any possible data loss) grml2iso will exit if the specified target.iso exists already. 45 | 46 | *-c *:: 47 | 48 | The content of the specified directory will be copied to the resulting multiboot Grml ISO. 49 | 50 | *-b *:: 51 | 52 | Use specified default bootoptions as default. 53 | 54 | *-f*:: 55 | 56 | Force the program to run and overwrite an existing ISO image. 57 | 58 | *-r *:: 59 | 60 | Remove specified boot parameter from existing command line. 61 | Can be specified multiple times. 62 | 63 | *-p *:: 64 | 65 | Execute grml2usb with the specified parameters. 66 | For a list of valid parameters have a look at the grml2usb(8) manual page. 67 | 68 | *-s *:: 69 | 70 | Generate a small ISO file which downloads the squashfs file from the specified URI. 71 | Due to current limitations in busyboxs wget and DNS resolution, an URL can not contain a hostname but an IP only. 72 | This is useful if you want to boot systems which support booting ISO image from your local system. 73 | Besides the ISO image this command also copies the squashfs file to the output directory. 74 | 75 | Usage examples 76 | -------------- 77 | 78 | # grml2iso -o /tmp/grml-multiboot.iso grml32-small_2020.06.iso grml64-small_2020.06.iso 79 | 80 | Create multiboot ISO /tmp/grml-multiboot.iso with grml32-small_2020.06.iso and grml64-small_2020.06.iso. 81 | 82 | # grml2iso -b 'lang=de ssh=passwd' -c /tmp/grml-content -o /srv/grml-multiboot.iso /srv/grml/grml32-small_2020.06.iso 83 | 84 | Create a new ISO with additional boot parameters and copy the content from /tmp/grml-content to the generated ISO image. 85 | 86 | # grml2iso -r quiet -r vga=791 -o /srv/grml-multiboot.iso /srv/grml64-small_2020.06.iso 87 | 88 | Create a new ISO and remove existing boot parameters quiet and vga=791. 89 | 90 | # GRML2USB=/srv/git/grml2usb/grml2usb grml2iso -o /srv/grml-multiboot.iso /srv/grml/grml32-small_2020.06.iso /srv/grml/grml64-medium_2020.06.iso 91 | 92 | Create multiboot ISO /srv/grml-multiboot.iso with grml32-small_2020.06.iso and grml64-medium_2020.06.iso using /srv/git/grml2usb/grml2usb as grml2usb script. 93 | 94 | # WRKDIR=/mnt/test/grml-tmp grml2iso -o /mnt/test/grml-multiboot.iso grml32-small_2020.06.iso grml64-small_2020.06.iso 95 | 96 | Use /mnt/test/grml-tmp as working directory for creating the multiboot ISO /mnt/test/grml-multiboot.iso with grml32-small_2020.06.iso and grml64-small_2020.06.iso. 97 | 98 | # grml2iso -p --skip-addons -o /srv/grml-multiboot.iso /srv/grml64-small_2020.06.iso /srv/grml64-small_2020.06.iso 99 | 100 | Don't copy the addons from the specified ISO images 101 | 102 | Bugs 103 | ---- 104 | Please report feedback, bug reports and wishes at https://github.com/grml/grml2usb/ 105 | 106 | [[X7]] 107 | Author 108 | ------ 109 | Michael Prokop 110 | -------------------------------------------------------------------------------- /tarball.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Filename: tarball.sh 3 | # Purpose: generate tarball for using grml2usb on non-Debian systems 4 | # Authors: grml-team (grml.org), (c) Michael Prokop 5 | # Bug-Reports: see http://grml.org/bugs/ 6 | # License: This file is licensed under the GPL v2 or any later version. 7 | ################################################################################ 8 | 9 | set -e 10 | 11 | VERSION=$(dpkg-parsechangelog | awk '/Version: / { print $2 }') 12 | DIR="grml2usb-${VERSION}" 13 | [ -d "$DIR" ] || mkdir "$DIR" 14 | 15 | cat > "${DIR}"/README << EOF 16 | README 17 | ------ 18 | 19 | grml2usb installs Grml ISO(s) on USB device for booting. 20 | 21 | This tarball provides all the necessary files for running grml2usb. 22 | Execute the script install.sh with root permissions to install the 23 | files provided by the tarball in the filesystem. 24 | 25 | Updating is possible via downloading the most recent tarball and 26 | executing install.sh again. 27 | 28 | If you want to remove grml2usb from your system just execute 29 | the provided uninstall.sh script with root permissions. 30 | 31 | Note: 32 | 33 | If you are using Debian (or a Debian based system like grml, Ubuntu,...) 34 | consider using the provided grml2usb Debian package: 35 | http://deb.grml.org/ => http://deb.grml.org/pool/main/g/grml2usb/ 36 | 37 | Please report bugs and feedback to Michael Prokop . 38 | EOF 39 | 40 | cat > "${DIR}"/install.sh << EOF 41 | #!/bin/sh 42 | 43 | set -e 44 | 45 | if [ \$(id -u) != 0 ] ; then 46 | echo "Error: become root before starting \$0" >& 2 47 | exit 1 48 | fi 49 | 50 | BASE="\$(dirname \$0)" 51 | 52 | printf "Installing files:\n" 53 | 54 | printf " - /usr/sbin/grml2usb\n" 55 | install -m 755 \${BASE}/grml2usb /usr/sbin/grml2usb 56 | 57 | printf " - /usr/sbin/grml2iso\n" 58 | install -m 755 \${BASE}/grml2iso /usr/sbin/grml2iso 59 | 60 | [ -d /usr/share/grml2usb/grub ] || mkdir -p /usr/share/grml2usb/grub 61 | printf " - /usr/share/grml2usb/grub/splash.xpm.gz\n" 62 | install -m 644 \${BASE}/splash.xpm.gz /usr/share/grml2usb/grub/splash.xpm.gz 63 | printf " - /usr/share/grml2usb/grub/grml.png\n" 64 | install -m 644 \${BASE}/grml.png /usr/share/grml2usb/grub/grml.png 65 | 66 | [ -d /usr/share/grml2usb/mbr ] || mkdir -p /usr/share/grml2usb/mbr 67 | printf " - /usr/share/grml2usb/mbr/mbrmgr\n" 68 | install -m 644 \${BASE}/mbrmgr /usr/share/grml2usb/mbr/mbrmgr 69 | printf " - /usr/share/grml2usb/mbr/mbrldr\n" 70 | install -m 644 \${BASE}/mbrldr /usr/share/grml2usb/mbr/mbrldr 71 | 72 | [ -d /usr/share/man/man8/ ] || mkdir -p /usr/share/man/man8 73 | printf " - /usr/share/man/man8/grml2usb.8.gz\n" 74 | install -m 644 \${BASE}/grml2usb.8.gz /usr/share/man/man8/grml2usb.8.gz 75 | 76 | printf "Finished installation.\n" 77 | EOF 78 | 79 | chmod 755 "${DIR}"/install.sh 80 | 81 | cat > "${DIR}"/uninstall.sh << EOF 82 | #!/bin/sh 83 | 84 | set -e 85 | 86 | if [ \$(id -u) != 0 ] ; then 87 | echo "Error: become root before starting \$0" >& 2 88 | exit 1 89 | fi 90 | 91 | for file in \\ 92 | /usr/sbin/grml2usb \\ 93 | /usr/sbin/grml2iso \\ 94 | /usr/share/grml2usb/grub/splash.xpm.gz \\ 95 | /usr/share/grml2usb/grub/grml.png \\ 96 | /usr/share/grml2usb/mbr/mbrmgr \\ 97 | /usr/share/grml2usb/mbr/mbrldr \\ 98 | /usr/share/man/man8/grml2usb.8.gz \\ 99 | ; do 100 | printf "Removing \$file: " 101 | rm -f \$file && printf "done\n" || printf "failed\n" 102 | done 103 | EOF 104 | 105 | chmod 755 "${DIR}"/uninstall.sh 106 | 107 | fakeroot debian/rules build 108 | 109 | # manpage 110 | cp grml2usb.8.adoc grml2usb-$VERSION/ 111 | cp grml2iso.8.adoc grml2usb-$VERSION/ 112 | gzip -9 --to-stdout grml2usb-$VERSION/grml2usb.8.adoc > grml2usb-$VERSION/grml2usb.8.gz 113 | gzip -9 --to-stdout grml2usb-$VERSION/grml2iso.8.adoc > grml2usb-$VERSION/grml2iso.8.gz 114 | rm grml2usb-$VERSION/grml2usb.8.adoc 115 | rm grml2usb-$VERSION/grml2iso.8.adoc 116 | 117 | # binaries, grub 118 | cp grml2usb grml2iso mbr/mbrldr mbr/mbrmgr grub/* grml2usb-$VERSION/ 119 | sed -i -e "s/PROG_VERSION = '\*\*\*UNKNOWN\*\*\*'/PROG_VERSION = '${VERSION}'/" grml2usb-$VERSION/grml2usb 120 | 121 | tar zcf grml2usb.tgz "${DIR}" 122 | 123 | rm -rf "${DIR}" 124 | md5sum grml2usb.tgz > grml2usb.tgz.md5 125 | 126 | case "$1" in 127 | --no-gpg) 128 | echo "Not signing grml2usb.tgz.md5 as requested via --no-gpg." 129 | echo "Do not forget to run gpg --clearsign grml2usb.tgz.md5 before uploading." 130 | ;; 131 | *) 132 | gpg --clearsign grml2usb.tgz.md5 133 | rm grml2usb.tgz.md5 134 | echo "Generated grml2usb.tgz and grml2usb.tgz.md5.asc of grml2usb $VERSION" 135 | ;; 136 | esac 137 | 138 | ## END OF FILE ################################################################# 139 | -------------------------------------------------------------------------------- /mbr/mbr.S: -------------------------------------------------------------------------------- 1 | ; $MirOS: src/sys/arch/i386/stand/mbr/mbr.S,v 1.13 2009/03/04 10:50:28 tg Exp $ 2 | ; Ported to nasm syntax 2024-10-04 by ch@grml.org 3 | 4 | ; Copyright (c) 2009 5 | ; Thorsten Glaser 6 | ; 7 | ; Provided that these terms and disclaimer and all copyright notices 8 | ; are retained or reproduced in an accompanying document, permission 9 | ; is granted to deal in this work without restriction, including un- 10 | ; limited rights to use, publicly perform, distribute, sell, modify, 11 | ; merge, give away, or sublicence. 12 | ; 13 | ; This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 14 | ; the utmost extent permitted by applicable law, neither express nor 15 | ; implied; without malicious intent or gross negligence. In no event 16 | ; may a licensor, author or contributor be held liable for indirect, 17 | ; direct, other damage, loss, or other issues arising in any way out 18 | ; of dealing in the work, even if advised of the possibility of such 19 | ; damage or existence of a defect, except proven that it results out 20 | ; of said person's immediate fault when using the work as intended. 21 | ;- 22 | ; Assemble commands: 23 | ; $ nasm -D__BOOT_VER=\"0AA6\" -DBOOTMANAGER mbr.S -o mbrmgr 24 | ; $ nasm -D__BOOT_VER=\"0AA6\" -DBOOT_QUIET mbr.S -o mbrldr 25 | 26 | bits 16 27 | section .text 28 | org 600h 29 | cpu 386 30 | 31 | global _start 32 | _start: xor eax,eax 33 | mov ss,ax 34 | mov sp,Lstack 35 | push eax 36 | popfd 37 | mov ds,ax 38 | mov es,ax 39 | mov si,Lbadr 40 | mov di,_start 41 | mov cx,0x0200 ; size of one sector 42 | push si ; load / return address 43 | push ax 44 | push Lmain 45 | rep movsb 46 | retf 47 | 48 | ; entry message 49 | Lemsg: db "Mir-" 50 | db __BOOT_VER 51 | %if %isdef(BOOTMANAGER) 52 | ; Lem are patch points 53 | db ": 0=" 54 | Lem00: db "00 1=" 55 | Lem01: db "00 2=" 56 | Lem02: db "00 3=" 57 | Lem03: db "00 4=hd0 5=fd0 Enter=default (timeout)", 0x0d, 0x0a 58 | %endif 59 | db ">", 0 60 | 61 | ; failure message 62 | Lfmsg: db "bad magic", 0x0d, 0x0a, 0 63 | 64 | %if 1 65 | ; okay boot message 66 | Lbmsg: db " OK", 0x0d, 0 67 | %endif 68 | 69 | ; output NUL-terminated string from ds:si 70 | Lotxt0: mov ah,0x0E 71 | mov bx,7 72 | int 0x10 73 | Lotxt: lodsb 74 | or al,al 75 | jnz Lotxt0 76 | ret 77 | 78 | Lmain: sti 79 | %if %isdef(BOOTMANAGER) 80 | ; patch the partition type values into the message 81 | mov di, Lem00 82 | mov al,[Lptab + 0x04] 83 | call LpBY 84 | mov di, Lem01 85 | mov al,[Lptab + 0x14] 86 | call LpBY 87 | mov di, Lem02 88 | mov al,[Lptab + 0x24] 89 | call LpBY 90 | mov di, Lem03 91 | mov al,[Lptab + 0x34] 92 | call LpBY 93 | %endif 94 | %if !%isdef(BOOT_QUIET) || %isdef(BOOTMANAGER) 95 | ;mov si,offset Lemsg 96 | mov si, Lemsg 97 | call Lotxt 98 | %endif 99 | 100 | ; fake invalid partition entry for MBR/FDD boot 101 | mov di, Lptab + 0x40 102 | xor eax,eax 103 | stosw 104 | inc ax 105 | stosw 106 | dec ax 107 | stosd 108 | stosd 109 | 110 | ; force bad magic if sector load fails 111 | mov [Lbmag],al 112 | 113 | %if %isdef(BOOTMANAGER) 114 | %if 0 ; see above, eax is already zero here 115 | xor ax,ax ; read CMOS clock ticks since midnight 116 | %endif 117 | int 0x1A ; 32-bit result in cx:dx 118 | mov di,cx ; save it in edi for later 119 | shl edi,16 120 | mov di,dx 121 | add edi,183 ; 10 seconds, rounded up one tick 122 | Lptmo equ $ - 4 ; offset of the "183" above 123 | 124 | ; input loop with timeout 125 | Lwkey: mov ah,1 126 | int 0x16 ; check if a key was pressed 127 | jnz Lgkey ; yeap 128 | ; delay loop 129 | xor ax,ax 130 | int 0x1A 131 | shl ecx,16 132 | mov cx,dx 133 | or al,al ; past midnight? 134 | jz Lsday ; no 135 | add ecx,1573040 ; should be 1572480, but according to RBIL… 136 | Lsday: cmp ecx,edi ; time is over? 137 | mov al,13 138 | ja Lfkey ; yep, fake a return keypress 139 | jmp Lwkey 140 | 141 | ; input loop without timeout 142 | Lgkey: mov ah,1 143 | int 0x16 ; check if a key was pressed 144 | jz Lgkey 145 | mov ah,0 146 | int 0x16 147 | %endif ; BOOTMANAGER 148 | Lfkey: mov bx, Lptab 149 | mov dl,0x80 ; drive to load from 150 | %if !%isdef(BOOTMANAGER) 151 | jmp Lscan 152 | %else 153 | sub al,13 154 | je Lscan ; CR / Return / Enter 155 | jb Lgkey ; invalid input 156 | sub al,('0' - 13) 157 | jb Lgkey ; invalid input 158 | cmp al,5 ; floppy 159 | ja Lgkey ; invalid input 160 | jb LdoHD ; hard disc 161 | mov dl,0 ; drive to load from 162 | dec ax ; 5 -> 4 163 | %endif 164 | LdoHD: shl al,4 ; 0..4 where 4 is virtual partition 165 | add bl,al ; we boot this one 166 | jmp Lboot 167 | 168 | ; scan the partition table for an active partition 169 | Lscan: mov al,[dpart] ; try hard-coded by fdisk(8) 'fdef' first 170 | cmp al,3 171 | jbe LdoHD 172 | Lspar: cmp byte [bx],0x80 173 | je Lboot ; found an active partition 174 | add bl,0x10 175 | cmp bl,0xFE ; BX = 0x07FE = Lptab + 0x40 176 | jb Lspar 177 | ; boot the virtual partition #4 (MBR) 178 | 179 | Lboot: ; try to boot, first LBA (we're on a HDD) then CHS 180 | mov [bx],dl ; drive (0x80 or 0x00) 181 | mov si, Lpblk ; LBA parameter block 182 | mov di,si 183 | mov ax,0x0010 184 | stosw ; size of LBA parameter block 185 | mov al,1 186 | stosw ; number of sectors to load 187 | pop ax 188 | push ax 189 | push bx 190 | stosw ; load address offset 191 | xor ax,ax 192 | stosw ; load address segment 193 | mov eax,[bx+8] 194 | stosd ; LBA offset of start sector (low 32 bit) 195 | xor ax,ax 196 | stosw ; high 32 bit 197 | stosw ; high 32 bit 198 | mov ah,0x42 ; LBA extended read 199 | call Lload ; try to boot that 200 | pop si ; edited partition table entry 201 | pop bx ; load offset (ES=CS=SS=DS=0000h) 202 | push bx 203 | push si 204 | mov ax,0x0201 ; CHS read 0x01 sectors 205 | mov cx,[si+2] ; cylinder; sector number 206 | mov dx,[si] ; head; drive number 207 | call Lload 208 | mov si, Lfmsg 209 | call Lotxt 210 | %if 0 211 | Lfail: jmp Lfail 212 | %else 213 | xor ax,ax 214 | int 0x16 215 | jmp 0xF000:0xFFF0 216 | %endif 217 | 218 | Lload: mov bp,4 ; number of tries 219 | Lldlp: pusha 220 | int 0x13 221 | popa 222 | jc Lldre ; error, try again 223 | cmp word [Lbmag],0xAA55 224 | jne Lldre ; bad magic, try again 225 | %if 0 226 | mov ax,0x0E0D ; output a carriage return 227 | xor bx,bx 228 | int 0x10 229 | %else 230 | mov si, Lbmsg 231 | call Lotxt 232 | %endif 233 | pop si ; Lload return address 234 | pop si ; partition table entry 235 | mov dl,[si] 236 | ; DS:SI point to partition table entry, DL is set 237 | cli ; be nice :) 238 | ret ; jump to 0000:7C00h 239 | Lldre: pusha 240 | xor ax,ax ; reset drive 241 | int 0x13 242 | popa 243 | dec bp ; another try left? 244 | jnz Lldlp 245 | ret 246 | 247 | %if %isdef(BOOTMANAGER) 248 | LpBY: mov ah,al 249 | shr al,4 250 | and ah,0x0F 251 | add ax,0x3030 252 | cmp al,0x39 253 | jbe LpBY1 254 | add al,7 255 | LpBY1: cmp ah,0x39 256 | jbe LpBY2 257 | add ah,7 258 | LpBY2: stosw 259 | ret 260 | %endif 261 | 262 | times 0x01b7 - ($-$$) db 0 263 | ; . = _start + 0x01B7 264 | dpart: db 0xFF ; default partition [0..3] or none 265 | 266 | Lntid: dd 0 ; Microsoft® NT® volume identifier 267 | Lpad1: dw 0 268 | 269 | ; . = _start + 0x01BE 270 | ; partition table 271 | Lptab: dd 0, 0, 0, 0 ; partition entry #0 272 | dd 0, 0, 0, 0 ; partition entry #1 273 | dd 0, 0, 0, 0 ; partition entry #2 274 | ; partition entry #3 + pre-installation hint 275 | dw 0, 0, 0, 0, 0 276 | ; . = _start + 0x01F8 277 | ; .size Lhint,2 278 | %if %isdef(BOOTMANAGER) 279 | Lhint: dw (Lptmo - _start) 280 | %else 281 | Lhint: dw 0xFFFF 282 | %endif 283 | Lpad2: dw 0, 0 284 | 285 | ; . = _start + 0x01FE 286 | times 510-($-$$) db 0 287 | Lpmag: dw 0xAA55 ; BIOS boot magic 288 | 289 | Lstack equ 0x4000 290 | Lpblk equ 0x5000 291 | 292 | Lbadr equ 0x7C00 293 | Lbmag equ Lbadr + 0x01FE 294 | 295 | -------------------------------------------------------------------------------- /grml2iso: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Filename: grml2iso 3 | # Purpose: create a multiboot grml ISO using grml2usb 4 | # Authors: Michael Prokop 5 | # Bug-Reports: see http://grml.org/bugs/ 6 | # License: This file is licensed under the GPL v2 or any later version. 7 | ################################################################################ 8 | 9 | set -e -o pipefail 10 | 11 | # make sure we have the sbin directories in our PATH to find grml2usb ootb 12 | PATH="${PATH}:/sbin:/usr/local/sbin:/usr/sbin" 13 | 14 | # adjust variables if necessary through environment {{{ 15 | # path to the grml2usb script you'd like to use 16 | [ -n "$GRML2USB" ] || GRML2USB='grml2usb' 17 | 18 | # support mkisofs as well as genisoimage 19 | if which xorriso >/dev/null 2>&1 ; then 20 | MKISOFS='xorriso -as mkisofs' 21 | elif which mkisofs >/dev/null 2>&1; then 22 | MKISOFS='mkisofs' 23 | elif which genisoimage >/dev/null 2>&1; then 24 | MKISOFS='genisoimage' 25 | else 26 | echo "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." >&2 27 | exit 1 28 | fi 29 | 30 | if ! which isohybrid >/dev/null 2>&1 ; then 31 | echo "Error: isohybrid executable not found (install syslinux/isolinux/syslinux-utils?)." >&2 32 | exit 1 33 | fi 34 | # }}} 35 | 36 | # helper stuff {{{ 37 | usage() { 38 | echo >&2 "Usage: $0 [OPTIONS] -o target.iso source1.iso [source2.iso ...]" 39 | echo >&2 " 40 | Options: 41 | -b Boot Params Additional boot parameters passed to grml2usb 42 | -c Directory Copy files from directory to generated ISO 43 | -f Force overwrite of existing target.iso 44 | -r BootParam Remove specified boot params. 45 | Can be specified multiple times. 46 | -p Add the specified parameter to the grml2usb 47 | commandline. For a list of valid parameters have 48 | a look at the grml2usb manpage. 49 | Can be specified multiple times. 50 | -s URI Generate a small ISO file which downloads the squashfs 51 | file from the specified URI. Please note that due to 52 | restrictions in the bootprocess only IPs are allowed. 53 | Supported protocols are: http and ftp 54 | -t Directory Directory that should be used for temporary files 55 | during build, instead of using a temporary directory 56 | created by mktemp(1). 57 | 58 | Examples: 59 | $0 -s http://192.168.23.42:8000/grml/ -o small.iso grml64-small_2021.07.iso 60 | 61 | Will generate a file small.iso which tries to download the squashfs file from 62 | http://192.168.23.42:8000/grml/ - the squashfs file is placed in the same 63 | output directory as the ISO file. 64 | " 65 | [ -n "$1" ] && exit $1 || exit 1 66 | } 67 | # }}} 68 | 69 | # command line handling {{{ 70 | [[ $# -gt 2 ]] || usage 1 71 | 72 | ISOFILE='' 73 | DIR='' 74 | ADD_OPTS='' 75 | FORCE='' 76 | URI='' 77 | typeset -a GRML2USB_OPTS 78 | while getopts fb:c:o:r:p:s:t: name; do 79 | case $name in 80 | o) ISOFILE="$OPTARG";; 81 | b) GRML2USB_OPTS+=(--bootoptions="$OPTARG");; 82 | c) DIR="$(readlink -f "$OPTARG")"; [ -n "$DIR" ] || { echo "Could not read $OPTARG - exiting" >&2 ; exit 1 ; } ;; 83 | f) FORCE='true';; 84 | r) GRML2USB_OPTS+=(--remove-bootoption="$OPTARG");; 85 | p) GRML2USB_OPTS+=("$OPTARG");; 86 | s) URI="$OPTARG";; 87 | t) WRKDIR="$(readlink -f "$OPTARG")";; 88 | ?) usage 2;; 89 | esac 90 | done 91 | 92 | # test for specified URI 93 | if [ -n "$URI" ] ; then 94 | GRML2USB_OPTS+=(--bootoptions="fetch=$URI") 95 | fi 96 | 97 | # make sure -o is specified 98 | [ -n "$ISOFILE" ] || usage 1 99 | 100 | # we don't to override any files by accident 101 | if [ -e "$ISOFILE" -a ! -n "$FORCE" ]; then 102 | echo "Error: target file $ISOFILE exists already." >&2 103 | exit 1 104 | fi 105 | 106 | if [ ! -z "$DIR" -a ! -d "$DIR" ] ; then 107 | echo "Error: specified parameter for -c is not a directory" >&2 108 | exit 1 109 | fi 110 | # }}} 111 | 112 | # we need root permissions for executing grml2usb {{{ 113 | if [[ $(id -u) != 0 ]]; then 114 | echo >&2 "Error: please run $0 as root." 115 | exit 1 116 | fi 117 | # }}} 118 | 119 | # check for grml2usb {{{ 120 | if [ ! -x "$(which $GRML2USB)" ] && [ ! -x "$GRML2USB" ] ; then 121 | echo "Error: Could not find grml2usb executable. Is /usr/sbin missing in PATH?" >&2 122 | echo "Tip: run GRML2USB=/usr/sbin/grml2usb grml2iso ... as workaround" >&2 123 | if [ -x "./$GRML2USB" ] ; then 124 | echo >&2 "If you executed grml2iso from the grml2usb repository use" 125 | echo >&2 "GRML2USB=./grml2usb $0 $*" 126 | fi 127 | exit 1 128 | fi 129 | # }}} 130 | 131 | # variables {{{ 132 | ORIG_DIR="$(pwd)" 133 | 134 | # normalise path 135 | case $ISOFILE in 136 | /*) ;; 137 | *) ISOFILE=$ORIG_DIR/$ISOFILE ;; 138 | esac 139 | # }}} 140 | 141 | # ensure to properly set up working directory {{{ 142 | WRKDIR_EXISTED='false' 143 | if [ -z "$WRKDIR" ] ; then 144 | WRKDIR="$(mktemp -d)" 145 | else 146 | [ -d "$WRKDIR" ] && WRKDIR_EXISTED='true' 147 | fi 148 | 149 | GRML2USB_OPTS+=(--tmpdir="$WRKDIR") 150 | 151 | rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp" 152 | mkdir -p "$WRKDIR/cddir" 153 | # }}}} 154 | 155 | # execute grml2usb with all ISOs you'd like to install {{{ 156 | # remove all parameters 157 | shift $(($OPTIND - 1)) 158 | 159 | $GRML2USB "${GRML2USB_OPTS[@]}" "$@" "$WRKDIR/cddir" 160 | # }}} 161 | 162 | # move syslinux to isolinux {{{ 163 | mv "$WRKDIR"/cddir/boot/syslinux "$WRKDIR"/cddir/boot/isolinux 164 | echo "menu label ^Isolinux prompt" > "$WRKDIR"/cddir/boot/isolinux/promptname.cfg 165 | echo "include hd.cfg" >> "$WRKDIR"/cddir/boot/isolinux/grmlmain.cfg 166 | # }}} 167 | 168 | # change to $WRKDIR {{{ 169 | # make sure $WRKDIR is an absolute path, otherwise accessing files 170 | # in it will fail later in the code path if user provided a 171 | # relative directory 172 | WRKDIR=$(realpath $WRKDIR) 173 | cd "$WRKDIR/cddir" 174 | # }}} 175 | 176 | # efi boot {{{ 177 | # default, independent of UEFI support 178 | BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat" 179 | UEFI_ENABLE=false 180 | 181 | case "$MKISOFS" in 182 | xorriso*) 183 | echo "Using xorriso for ISO generation." 184 | if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then 185 | echo "Disabling (U)EFI boot support since xorriso version is not recent enough." 186 | else 187 | echo "xorriso with -eltorito-alt-boot support present" 188 | UEFI_ENABLE=true 189 | 190 | if ! [ -r "${WRKDIR}/cddir/boot/efi.img" ] ; then 191 | echo "Warning: File /boot/efi.img not found, not extending boot arguments for (U)EFI boot." 192 | UEFI_ENABLE=false 193 | else 194 | echo "/boot/efi.img found, extending boot arguments for (U)EFI boot." 195 | if ! [ -r /usr/lib/ISOLINUX/isohdpfx.bin ] ; then 196 | echo "Error: /usr/lib/ISOLINUX/isohdpfx.bin not available, required for xorriso/isohybrid though." >&2 197 | echo "Hint: make sure isolinux is installed." >&2 198 | exit 1 199 | else 200 | BOOT_ARGS+=" -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot" 201 | BOOT_ARGS+=" -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -eltorito-alt-boot -e boot/efi.img -no-emul-boot -isohybrid-gpt-basdat -no-pad" 202 | fi 203 | fi 204 | fi 205 | ;; 206 | *) 207 | echo "Using $MKISOFS for ISO generation (lacking UEFI option), disabling (U)EFI boot support." 208 | ;; 209 | esac 210 | # }}} 211 | 212 | # adjust ISO for small output if necessary {{{ 213 | if [ -n "$URI" ] ; then 214 | bootloader_files=$(find . -name "*.cfg" -type f) 215 | bootloader_files+=" " 216 | bootloader_files+=$(find . -name "*.lst" -type f) 217 | output_dir=$(dirname "$ISOFILE") 218 | for squashfs in $(find . -name *.squashfs) ; do 219 | media_path="$(dirname "$squashfs")" 220 | filename="$(basename "$squashfs")" 221 | target="$output_dir/$filename" 222 | if [ -f "$target" ] && [ ! -n "$FORCE" ] ; then 223 | echo >&2 "Warning: $target already exists, and -force not specified, not overwriting" 224 | else 225 | mv $squashfs $target 226 | OUTPUT_FILES+=("$target") 227 | fi 228 | sed -i -e "s#^\(^.*$media_path.*\)\($URI\)\(.*$\)#\1$URI/$filename\3#g" $bootloader_files 229 | 230 | done 231 | fi 232 | # }}} 233 | 234 | # copy specified directory to cd {{{ 235 | if [ -n "$DIR" ] ; then 236 | echo >&2 "Copying ${DIR} to generated ISO" 237 | for param in GRML_NAME VERSION RELEASENAME DATE SHORT_NAME \ 238 | VERSION BOOTID RELEASE_INFO ; do 239 | EXCLUDE_PARAM="$EXCLUDE_PARAM --exclude **%${param}%**" 240 | done 241 | rsync -a ${DIR}/ $EXCLUDE_PARAM . 242 | fi 243 | 244 | # adjust files from overlay directory 245 | for GRML_VERSION_FILE in $(find . -name grml-version) ; do 246 | GRML_NAME=$(awk '{print $1}' "$GRML_VERSION_FILE") 247 | VERSION=$(awk '{print $2}' "$GRML_VERSION_FILE") 248 | RELEASENAME=$(sed 's/.*- \(.*\).*\[.*/\1/' "$GRML_VERSION_FILE") 249 | DATE=$(sed 's/.*\[\(.*\)].*/\1/' "$GRML_VERSION_FILE") 250 | SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')" 251 | RELEASE_INFO="$GRML_NAME $VERSION - $RELEASENAME" 252 | BOOTID=$(cat conf/bootid.txt) 253 | 254 | for param in GRML_NAME VERSION RELEASENAME DATE SHORT_NAME \ 255 | RELEASE_INFO BOOTID ; do 256 | value="$(eval echo '$'"$param")" 257 | 258 | # copy parameterized files from the overlay directory 259 | for file in $(find ${DIR} -name "*%$param%*") ; do 260 | file=${file##$DIR/} 261 | target_dir="$(dirname ${file})" 262 | mkdir -p "$target_dir" || true 263 | cp -r ${DIR}/${file} ./${target_dir}/"$(basename ${file/\%${param}\%/$value})" 264 | done 265 | 266 | # adjust config files 267 | for file in ./boot/isolinux/*.cfg ./boot/isolinux/*.msg \ 268 | ./boot/grub/*.cfg ; do 269 | sed -i "s/%$param%/$value/g" ${file} 2>/dev/null || true 270 | done 271 | done 272 | done 273 | # }}} 274 | 275 | # generate the CD/DVD ISO {{{ 276 | $MKISOFS -V 'grml-multiboot' -l -r -J $BOOT_ARGS \ 277 | -o "$ISOFILE" . 278 | # }}} 279 | 280 | # cleanup {{{ 281 | cd "$ORIG_DIR" 282 | sync 283 | rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp" 284 | [[ $WRKDIR_EXISTED = 'false' ]] && rmdir "$WRKDIR" 285 | echo "Generated $ISOFILE" 286 | if [ -n "$URI" ] ; then 287 | echo " 288 | Information: 289 | ============== 290 | You requested to generate a small ISO image. Your generated 291 | ISO image $ISOFILE does _not_ contain the squashfs files from 292 | the source ISO images. 293 | 294 | You have to provide the extracted squashfs files under $URI. 295 | 296 | ISO image: $ISOFILE 297 | Squashfs files: ${OUTPUT_FILES[@]} 298 | URI: $URI 299 | " 300 | fi 301 | # }}} 302 | 303 | ## EOF ######################################################################### 304 | # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2 305 | -------------------------------------------------------------------------------- /grml2usb.8.adoc: -------------------------------------------------------------------------------- 1 | grml2usb(8) 2 | =========== 3 | 4 | Name 5 | ---- 6 | grml2usb - install Grml ISO(s) on USB device for booting 7 | 8 | Synopsis 9 | -------- 10 | grml2usb [ options ] 11 | 12 | ******************************************************************************* 13 | Important! The Grml team does not take responsibility for loss of any data! 14 | ******************************************************************************* 15 | 16 | [[introduction]] 17 | Introduction 18 | ------------ 19 | 20 | grml2usb installs Grml on a given partition of your USB device and makes 21 | it bootable. It provides multiboot ISO support, meaning you can specify 22 | several Grml ISOs on the command line at once and select the Grml 23 | flavour you would like to boot on the bootprompt then. Note that the 24 | *first* ISO specified on the grml2usb command line will become the 25 | default one (that's the one that will boot when just pressing enter on 26 | the bootprompt or wait until the boot timeout matches). 27 | 28 | [IMPORTANT] 29 | By default a compatible master boot record (MBR) is installed on the device 30 | (being for example /dev/sdX when executing 'grml2usb grml.iso /dev/sdX1') and 31 | syslinux is being used as default bootloader. Avoid installation of the default 32 | MBR using the '--skip-mbr' option or if you encounter any problems with the 33 | default MBR consider using '--syslinux-mbr' instead. 34 | 35 | [[options]] 36 | Options 37 | ------- 38 | 39 | ISO[s] should be the path to one or multiple grml-ISOs and/or the path to 40 | the currently running live-system (being /run/live/medium). 41 | 42 | The device either might be a device name like /dev/sdX1 or a directory. When 43 | specifying a device name the device is mounted automatically. When specifying a 44 | directory grml2usb is assuming that you did set up a bootloader on your own (or 45 | don't need one) and a bootloader won't be installed automatically. 46 | 47 | The following options are supported: 48 | 49 | *--bootoptions=...*:: 50 | 51 | Use specified bootoptions as default. To use flavour name as a argument for a 52 | boot parameter use %flavour which will be expanded to the flavour name. To add 53 | multiple bootoptions you can specify the option multiple time. 54 | 55 | *--bootloader-only*:: 56 | 57 | Do *not* copy files but instead just install a bootloader. Note that the boot 58 | addons are copied to /boot/addons at this stage as well. If you want to skip 59 | copying the boot addons consider using the --skip-addons option. 60 | 61 | *--copy-only*:: 62 | 63 | Copy files only but do *not* install a bootloader. 64 | 65 | *--dry-run*:: 66 | 67 | Avoid executing commands, instead show what would be executed. 68 | Warning: please notice that the ISO has to be mounted anyway, otherwise 69 | identifying the Grml flavour would not be possible. 70 | 71 | *--format*:: 72 | 73 | Format specified partition with FAT. 74 | **Important:** this will destroy any existing data on the specified partition! 75 | 76 | *--force*:: 77 | 78 | Force any (possible dangerous) actions requiring manual interaction (like 79 | --format). 80 | 81 | *--grub*:: 82 | 83 | Install grub bootloader instead of (default) syslinux. 84 | 85 | *--grub-mbr*:: 86 | 87 | Install grub into MBR (Master Boot Record) instead of PBR (Partition Boot 88 | Record). Check out <> for further details. 90 | 91 | *--help*:: 92 | 93 | Display usage information and exit. 94 | 95 | ////////////////////////////////////////////////////////////////////////// 96 | *--initrd=...*:: 97 | 98 | Install specified initrd instead of the default. You might want to specify 99 | option *--kernel* as well. (Be aware when using multiboot setup.) 100 | [Notice: not implemented yet.] 101 | ////////////////////////////////////////////////////////////////////////// 102 | 103 | ////////////////////////////////////////////////////////////////////////// 104 | *--kernel=...*:: 105 | 106 | Install specified kernel instead of the default. You might want to specify 107 | option *--initrd* as well. (Be aware when using multiboot setup.) 108 | [Notice: not implemented yet.] 109 | ////////////////////////////////////////////////////////////////////////// 110 | 111 | *--mbr-menu*:: 112 | 113 | Install master boot record (MBR) with integrated boot menu: interactively choose 114 | the partition to boot from, with a timeout to load the default partition, or 115 | boot from floppy. When NOT using the --mbr-menu option a MBR with LBA and large 116 | disc support but without an integrated boot menu is installed (so it's not 117 | visible at all but instead directly jumps to the bootloader - being grub or 118 | syslinux). Note: This options is available only when using the default MBR and 119 | won't have any effect if you're using the '--syslinux-mbr' option. 120 | 121 | *--quiet*:: 122 | 123 | Do not output anything but just errors on console. 124 | 125 | *--skip-addons*:: 126 | 127 | Do not install /boot/addons/ files (like dos, grub, memdisk,...). 128 | 129 | *--remove-bootoption=...*:: 130 | 131 | Remove specified bootoption (could be a regex) from existing boot options. Use 132 | multiple entries for removing different bootoptions at once. 133 | 134 | *--skip-bootflag*:: 135 | 136 | Do not check for presence of boot flag on target device. 137 | 138 | *--skip-grub-config*:: 139 | 140 | Skip generation of grub configuration files. By default the configuration 141 | files for syslinux *and* grub will be written so you've a working configuration 142 | file no matter whether you're using grub or syslinux as bootloader. 143 | 144 | *--skip-mbr*:: 145 | 146 | Do not touch/install the master boot record (MBR). 147 | 148 | *--skip-syslinux-config*:: 149 | 150 | Skip generation of syslinux configuration files. By default the configuration 151 | files for syslinux *and* grub will be written so you've a working configuration 152 | file no matter whether you're using grub or syslinux as bootloader. 153 | 154 | *--skip-usb-check*:: 155 | 156 | Skip check to verify whether given device is a removable device. 157 | Some USB devices are known to report wrong information, when using 158 | such a device you can skip grml2usb's removable device check. 159 | 160 | *--syslinux*:: 161 | 162 | This option is deprecated and is being left only for backwards compatibility 163 | reasons. Syslinux is the default bootloader of grml2usb and therefore the 164 | '--syslinux' option doesn't have any effects. If you do not want to use syslinux 165 | as bootloader consider using the '--grub' option. 166 | 167 | *--syslinux-mbr*:: 168 | 169 | Install syslinux' master boot record (MBR, which is booting from the partition 170 | with the "active" flag set) instead of the default one. If you encounter any 171 | problems with the default MBR you can try using the syslinux MBR instead. If 172 | that works for you please <> so we can adjust our default 173 | MBR accordingly. 174 | 175 | ////////////////////////////////////////////////////////////////////////// 176 | *--squashfs=*:: 177 | 178 | Install specified squashfs file instead of the default. 179 | [Notice: not implemented yet.] 180 | ////////////////////////////////////////////////////////////////////////// 181 | 182 | ////////////////////////////////////////////////////////////////////////// 183 | *--uninstall*:: 184 | 185 | Uninstall Grml ISO files. 186 | [Notice: not implemented yet.] 187 | ////////////////////////////////////////////////////////////////////////// 188 | 189 | *-v*, *--version*:: 190 | 191 | Return version and exit. 192 | 193 | *--verbose*:: 194 | 195 | Enable verbose mode. 196 | 197 | Developers Corner 198 | ----------------- 199 | 200 | [[directory-layout]] 201 | Directory layout on USB device 202 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 203 | 204 | boot/ -> 205 | |-- addons/ 206 | | |-- ... [as provided on ISO] 207 | |-- release/ 208 | | |-- grml/ 209 | | | |-- vmlinuz [Kernel] 210 | | | |-- initrd.gz [initramfs] 211 | | |-- grml64 212 | | | |-- vmlinuz [Kernel] 213 | | | |-- initrd.gz [initramfs] 214 | | |-- grml-small 215 | | | |-- vmlinuz 216 | | | |-- initrd.gz 217 | | `-- grml64-small 218 | | |-- vmlinuz 219 | | |-- initrd.gz 220 | |-- grub/ 221 | | |-- grml.png [graphical bootsplash background image for grub2] 222 | | |-- grub.cfg [configuration file for grub2] 223 | `-- syslinux/ 224 | |-- grml.png [graphical bootsplash background image for syslinux] 225 | |-- syslinux.cfg [main configuration file for syslinux] 226 | `-- [....] [several further config files for syslinux] 227 | 228 | grml/ 229 | |-- grml2usb.txt [not yet implemented] 230 | |-- grml-cheatcodes.txt [list of bootoptions for Grml] 231 | |-- grml-version.txt [file containing information about grml-version] 232 | |-- LICENSE.txt [license information] 233 | |-- md5sums [md5sums of original ISO] 234 | |-- README.txt [informational text] 235 | `-- web/ [browser related files] 236 | |-- index.html 237 | |-- style.css 238 | `-- images/ 239 | |-- button.png 240 | |-- favicon.png 241 | |-- linux.jpg 242 | `-- logo.png 243 | 244 | live/ 245 | |-- grml/ 246 | | |-- filesystem.module [module specifying which squashfs should be used for grml] 247 | | `-- grml.squashfs [squashfs file for grml] 248 | |-- grml-small/ 249 | | |-- filesystem.module [module specifying which squashfs should be used for grml-small] 250 | | `-- grml-small.squashfs [squashfs file for grml-small] 251 | `-- ... 252 | 253 | [[source]] 254 | Grabbing the source 255 | ~~~~~~~~~~~~~~~~~~~ 256 | 257 | % git clone https://github.com/grml/grml2usb.git 258 | 259 | [[debugging]] 260 | Developers Debugging Hints 261 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 262 | 263 | To play with grml2usb you can avoid using a real device via a loopback file 264 | setup, like: 265 | 266 | # dd if=/dev/zero of=~/loopback bs=1M count=100 # adjust size to your needs 267 | # losetup /dev/loop1 ~/loopback 268 | 269 | Then create according partitions either running for example: 270 | 271 | # echo -en "n\np\n1\n\n\nt\n6\na\n1\n w\n" | fdisk /dev/loop1 272 | 273 | or: 274 | 275 | # parted /dev/loop1 -s "mkpart primary fat32 0 -1s mkfs 1 fat32" 276 | 277 | Finally create a filesystem and execute grml2usb as needed: 278 | 279 | # mkfs.vfat /dev/loop1 280 | # grml2usb --bootloader-only /grml/isos/grml-full-2025.08-amd64.iso /dev/loop1 281 | 282 | [[performance-tracing]] 283 | Performance tracing 284 | ~~~~~~~~~~~~~~~~~~~ 285 | 286 | # blktrace -d /dev/sdX -o - | blkparse -i - 287 | # grml2usb grml-full-2025.08-amd64.iso /dev/sdX1 288 | 289 | [[troubleshooting]] 290 | Troubleshooting and Pitfalls when booting 291 | ----------------------------------------- 292 | 293 | Here is a list of common error messages from BIOS/bootloader when trying to boot 294 | from USB. 295 | 296 | /////////////////////////////////////////////////////////// 297 | TODO: better list type for the error message / reason part? 298 | See http://www.methods.co.nz/asciidoc/userguide.html 299 | /////////////////////////////////////////////////////////// 300 | 301 | [horizontal] 302 | *Error message*:: ran out of input data. System halted 303 | 304 | *Reason*:: Everything OK, except for the filesystem used on your USB device. So 305 | instead of fat16 you are using for example fat32. Fix: use the appropriate 306 | filesystem (fat16 for USB flash drive usually). The Bootsplash might be displayed, the 307 | kernel loads but you very soon get the error message. 308 | 309 | *Error message*:: Invalid operating system 310 | 311 | *Reason*:: the partition layout is not ok. Very probably there's no primary 312 | partition (/dev/sdX{1..4}) or none has the flag 'bootable' set. 313 | 314 | *Error message*:: Boot error. 315 | 316 | *Reason*:: Some BIOSses offer different modes for USB booting. The proper mode 317 | to boot a USB stick is USB-HDD. If that doesn’t work or is not supported by your 318 | system, you need to format your USB-Stick as USB-ZIP. To do this, syslinux 319 | contains an utility called mkdiskimage, which you can use to re-format your USB 320 | stick in USB-ZIP format running 'mkdiskimage -4 /dev/sdX 1 64 32'. Please be 321 | aware that this procedure will erase all data on your stick. After executing 322 | mkdiskimage just continue installing as usual (grml2usb ... /dev/sdX4). Note 323 | that this is not going to work for any device larger than 8 GB, since 324 | mkdiskimage only supports 1024c 256h 63s. For a more detailed explanation, refer 325 | to /usr/share/doc/syslinux-common/usbkey.txt. 326 | 327 | *Error message*:: No operating system found. 328 | 329 | *Reason*:: you forgot to set the boot-flag on the partition. Or there really isn't 330 | any operating system at all. :) 331 | 332 | *Error message*:: kernel-panic: unable to mount root-fs... 333 | 334 | *Reason*:: Kernel boots but fails to find the root filesystem. The root= 335 | argument in your kernel commandline is pointing to the wrong device. Adjust 336 | root=..., consider using root=UUID=.... 337 | 338 | *Error message*:: Could not find kernel image: ... 339 | 340 | *Reason*:: either a broken isolinux/syslinux version or a broken BIOS. Check out 341 | whether the vendor provides a BIOS update or if using bootloader grub instead of 342 | isolinux/syslinux fixes the problem. 343 | 344 | [[faq]] 345 | Frequently Asked Questions (FAQ) 346 | -------------------------------- 347 | 348 | [[download]] 349 | Where can I get grml2usb? 350 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 351 | 352 | grml2usb is available as Debian package via link:https://deb.grml.org/[the 353 | grml-testing Debian repository]. 354 | 355 | If you do not want to (or can't) use the grml2usb Debian package you can either 356 | use the grml2usb git tree running: 357 | 358 | git clone https://github.com/grml/grml2usb.git 359 | cd grml2usb 360 | make -C mbr 361 | sudo ./grml2usb ... 362 | 363 | [NOTE] 364 | It is *NOT* enough to have just the grml2usb script itself without the according 365 | files provided either via the Debian package or the git tree. 366 | 367 | [[dd]] 368 | Why can't I just dd the ISO to a USB device? 369 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 370 | 371 | Well, you can. :) Starting with Grml 2009.10 the ISOs are dd-able straight out-of-the-box. 372 | 373 | [IMPORTANT] 374 | Note that ANY existing data on your USB device will be destroyed when 375 | using the dd approach. 376 | 377 | This allows you to dd the Grml ISO to your USB device (use for example 378 | link:http://www.chrysocome.net/rawwrite[rawwrite] if you've just a Windows 379 | system available) running: 380 | 381 | % dd if=grml-full-2025.08-amd64.iso of=/dev/sdX 382 | 383 | where /dev/sdX is your USB device. Of course this doesn't provide such a 384 | flexible system like with grml2usb (no multi-ISO setup, no additional default 385 | bootoptions,...) but it's a nice way to get a working USB boot setup if you 386 | don't have grml2usb available. 387 | 388 | [[grml2usb-vs-dd]] 389 | What's the difference between grml2usb and just using dd? 390 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 391 | 392 | grml2usb does not remove any data from your USB device and does not alter the 393 | partition table at all. grml2usb provides multi-ISO support, support for adding 394 | default bootoptions and selecting the bootloader (syslinux vs. grub) without 395 | having to manually touch the ISO at all. 396 | 397 | [[grml2iso]] 398 | What's grml2iso? 399 | ~~~~~~~~~~~~~~~~ 400 | 401 | grml2iso is a script which uses grml2usb to generate a multiboot ISO out of 402 | several Grml ISOs. See 'man grml2iso' for further details. 403 | 404 | [[grub-install-xfs_freeze]] 405 | grub-install complains about /sbin/grub-install and/or xfs_freeze?! 406 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 407 | 408 | The following message: 409 | 410 | You shouldn't call /sbin/grub-install. Please call /usr/sbin/grub-install instead! 411 | xfs_freeze: specified file ["/tmp/tmpqaBK6z/boot/grub"] is not on an XFS filesystem 412 | 413 | This is "normal". grub-install sends those messages to stderr. To avoid hiding any 414 | possible real error messages grml2usb doesn't ignore those messages. 415 | 416 | [[unary-operator]] 417 | grub-install complains about a unary operator?! 418 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 419 | 420 | The following message: 421 | 422 | '/usr/sbin/grub-install: line 374: [: =: unary operator expected' 423 | 424 | This is "normal". Just ignore it. (It usually doesn't appear 425 | on the second invocation on the same device.) 426 | 427 | [[unknown-filesystem]] 428 | grub-install fails with grub-probe: error: unknown filesystem?! 429 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 430 | 431 | The following message: 432 | 433 | grub-probe: error: unknown filesystem 434 | Auto-detection of a filesystem module failed. 435 | Please specify the module with the option `--modules' explicitly. 436 | 437 | usually means that the device partition table says something else than the 438 | filesystem on the device. For example using FAT16 as filesystem type and 439 | using FAT32 as filesystem on the partition will not work. Either set filesystem 440 | type to FAT32 or format the partition using FAT16. It is essential that 441 | device partition table and filesystem use the same filesystem type. 442 | 443 | [[mbr-vs-pbr]] 444 | grub-setup fails after Attempting to install GRUB to a partition instead of the MBR?! 445 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 446 | 447 | The following message: 448 | 449 | grub-setup: warn: Attempting to install GRUB to a partition instead of the MBR. This is a BAD idea. 450 | grub-setup: warn: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and its use is discouraged. 451 | grub-setup: error: Cannot read `/grub/core.img' correctly 452 | 453 | appears when using grub2 versions older than 1.98 as those version introduced a 454 | regression which avoids that grub is being installed into a partition (PBR, 455 | Partition Boot Record) instead of MBR (Master Boot Record). 456 | 457 | To work around this issue you can either 1) upgrade to grub versions >=1.98, 2) 458 | install grub into the MBR (Master Boot Record) using the '--grub-mbr' option of 459 | grml2usb or 3) switch to syslinux as bootmanager (just drop the '--grub' 460 | option). 461 | 462 | [[splash-xpm]] 463 | I'm getting something like "Error: /usr/share/grml2usb/grub/splash.xpm.gz can not be read"!? 464 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 465 | 466 | Looks like you've only the grml2usb script itself available. Please make sure 467 | you've the grml2usb Debian package installed. The most resent stable version is 468 | available via link:https://deb.grml.org/[the grml-testing Debian repository]. If 469 | you do not have a Debian system please see section <> in this FAQ. 471 | 472 | [[fat]] 473 | Why do I have to use a FAT16/FAT32 filesystem? 474 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 475 | 476 | Syslinux (currently) does not support any other filesystems besides FAT16/FAT32 477 | (though that's a sane default if you want to share your files with other 478 | (operating) systems). If you want to use a different filesystem (like ext2/3) 479 | use the bootloader grub instead using grml2usb's '--grub' option. 480 | 481 | [[cool-idea]] 482 | I think I've got a really cool idea! 483 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 484 | 485 | Great! Please check out 486 | link:https://github.com/grml/grml2usb/blob/master/TODO[the TODO file]. 487 | Feel free to <>. Patches highly 488 | appreciated. 489 | 490 | [[booting-from-usb]] 491 | I've problems with booting from USB. 492 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 493 | 494 | Check out <>. 495 | 496 | [[found-a-bug]] 497 | I've found a bug! 498 | ~~~~~~~~~~~~~~~~~ 499 | 500 | Please <>. Please provide usage examples and output 501 | of your grml2usb commandline (consider using the "--verbose" option). 502 | 503 | [[usage-examples]] 504 | Usage examples 505 | -------------- 506 | 507 | # grml2usb /home/grml/grml-full-2025.08-amd64.iso /dev/sdX1 508 | 509 | Install specified ISO on device /dev/sdX1. 510 | 511 | # grml2usb /home/grml/grml-full-2025.08-amd64.iso /home/grml/grml-full-2025.08-arm64.iso /dev/sdX1 512 | 513 | Install specified ISOs on device /dev/sdX1 for multibooting ISOs. 514 | 515 | # grml2usb /run/live/medium /dev/sdX1 516 | 517 | Install currently running Grml live system on device /dev/sdX1. 518 | 519 | # grml2usb /run/live/medium /home/grml/grml-full-2025.08-amd64.iso /dev/sdX1 520 | 521 | Install currently running Grml live system and the specified 522 | ISO on device /dev/sdX1 for multibooting. 523 | 524 | # grml2usb --format /home/grml/grml-full-2025.08-amd64.iso /dev/sdX1 525 | 526 | Install specified ISO on device /dev/sdX1 and format partition /dev/sdX1 with 527 | FAT filesystem. 528 | 529 | # grml2usb --grub --grub-mbr /home/grml/grml-full-2025.08-amd64.iso /dev/sdX1 530 | 531 | Install specified ISO on device /dev/sdX1 and use grub as bootloader (instead of 532 | syslinux being the default) and install a master boot record (MBR) to the MBR of 533 | /dev/sdX. 534 | 535 | # grml2usb --bootoptions="lang=de ssh=mysecret" grml-full-2025.08-amd64.iso /dev/sdX1 536 | # grml2usb --bootoptions="lang=de" --bootoptions="ssh=mysecret" grml-full-2025.08-amd64.iso /dev/sdX1 537 | 538 | Install specified ISO on device /dev/sdX1 and use "lang=de ssh=mysecret" as 539 | default bootoptions. 540 | 541 | 542 | # grml2usb --remove-bootoption="vga=791" --remove-bootoption="nomce" grml-full-2025.08-amd64.iso /dev/sdX1 543 | 544 | Install specified ISO on device /dev/sdX1 remove vga=791 and nomce from existing bootoptions. 545 | 546 | # grml2usb --bootoptions="persistent-path=%flavour_name" grml-full-2025.08-amd64.iso grml-full-2025.08-arm64.iso /dev/sdX1 547 | 548 | Install specified ISOs on device /dev/sdx and add parameter persistent-path 549 | to every menu entry. %flavour_name will be expanded to the flavour of the specific 550 | iso, e.g. grml64 and grml. 551 | 552 | [[resources]] 553 | Online Resources 554 | ---------------- 555 | 556 | Check out the link:https://grml.org/grml2usb/[grml2usb webpage], the 557 | link:https://github.com/grml/grml2usb[grml2usb git repository] and the 558 | wiki for link:https://github.com/grml/grml/wiki/persistency[persistency]. 559 | 560 | [[bugs]] 561 | Bugs 562 | ---- 563 | Please report feedback, bugreports and wishes <>. 564 | 565 | [[author]] 566 | Author 567 | ------ 568 | Michael Prokop 569 | 570 | ///////////////////////////////////////////////////////////////// 571 | https://unetbootin.sourceforge.net/ 572 | https://fedorahosted.org/liveusb-creator/ 573 | ///////////////////////////////////////////////////////////////// 574 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | grml2usb (0.20.10) unstable; urgency=medium 2 | 3 | [ Chris Hofstaedtler ] 4 | * [e903f89] Enable dependabot for GitHub Actions 5 | * [8cf171e] Replace GitHub workflows 6 | * [1e2562c] Rename asciidoc files to *.adoc 7 | * [1b073fb] Add README.md 8 | 9 | -- Chris Hofstaedtler Mon, 03 Nov 2025 12:54:33 +0100 10 | 11 | grml2usb (0.20.9) unstable; urgency=medium 12 | 13 | * [99d1520] d/copyright: Remove old FSF address 14 | 15 | -- Chris Hofstaedtler Tue, 26 Aug 2025 20:02:33 +0200 16 | 17 | grml2usb (0.20.8) unstable; urgency=medium 18 | 19 | * [bc49898] Stop mentioning specific addons 20 | * [23bf0c7] Remove support for kernels named linux26 21 | * [886a630] Remove grub1 details 22 | * [8d83006] Remove disabled doc part about --squashfs 23 | * [cb53e5a] Remove syslinux < 4.0 specifics 24 | * [17726f0] Update grml ISO in examples 25 | 26 | -- Chris Hofstaedtler Sun, 17 Aug 2025 12:34:08 +0200 27 | 28 | grml2usb (0.20.7) unstable; urgency=medium 29 | 30 | [ Chris Hofstaedtler ] 31 | * [2722899] GHA CI: revert back to ubuntu-latest 32 | 33 | [ Christopher Bock ] 34 | * [e218516] grml2usb.8: cleanup link, add wiki link for persistence 35 | * [9afefbb] replace fat16 command with format 36 | 37 | -- Michael Prokop Fri, 15 Aug 2025 12:05:26 +0200 38 | 39 | grml2usb (0.20.6) unstable; urgency=medium 40 | 41 | * [669ff7b] doc: remove backslashes from options 42 | * [2a47e65] doc/Makefile: remove scp leftovers 43 | * [2a9b458] Makefile: remove scp leftovers 44 | * [e5bea18] python: apply current black style 45 | 46 | -- Chris Hofstaedtler Tue, 04 Mar 2025 23:25:48 +0100 47 | 48 | grml2usb (0.20.5) unstable; urgency=medium 49 | 50 | * [804d407] Fix updating bootid for isolinux installs 51 | 52 | -- Chris Hofstaedtler Thu, 19 Dec 2024 17:31:56 +0100 53 | 54 | grml2usb (0.20.4) unstable; urgency=medium 55 | 56 | * [7538f7b] Fix crash: expected str, bytes or os.PathLike object, not list 57 | * [f087d75] Add smoke test 58 | * [026d659] Make blockdev --rereadpt optional 59 | * [4cbd342] Introduce automatic bootloader selection 60 | 61 | -- Chris Hofstaedtler Thu, 19 Dec 2024 02:00:26 +0100 62 | 63 | grml2usb (0.20.3) unstable; urgency=medium 64 | 65 | * [2163d31] migrate from optparse to argparse 66 | * [966c17b] fix missed execution of function 67 | * [a29b826] remove upgrade path from 15 years ago 68 | * [d3339d2] doc: remove isohybrid hint 69 | 70 | -- Chris Hofstaedtler Sat, 07 Dec 2024 16:08:26 +0100 71 | 72 | grml2usb (0.20.2) unstable; urgency=medium 73 | 74 | [ Michael Prokop ] 75 | * [4141028] Add debian/gbp.conf to set expected debian tag + dch 76 | settings 77 | 78 | [ Chris Hofstaedtler ] 79 | * [b344d41] Add .github/FUNDING.yml 80 | * [257aee3] Copy bootaa64.efi if available (#56) 81 | 82 | -- Michael Prokop Sat, 23 Nov 2024 13:50:29 +0100 83 | 84 | grml2usb (0.20.1) unstable; urgency=medium 85 | 86 | [ crpb ] 87 | * debian: update Vcs-Git and Vcs-Browser 88 | 89 | [ Chris Hofstaedtler ] 90 | * Loosen dependency on grub2. 91 | Avoid pulling in non-UEFI grub on amd64, if UEFI grub is already 92 | installed. Also necessary to allow installing on arm64. 93 | 94 | -- Chris Hofstaedtler Fri, 08 Nov 2024 18:09:18 +0100 95 | 96 | grml2usb (0.20.0) unstable; urgency=medium 97 | 98 | [ Chris Hofstaedtler ] 99 | * [8143af6] Use nasm to assemble mbr 100 | * [bb80820] debian: make grml2usb package Architecture: all 101 | * [e055635] debian: Do not run codecheck 102 | 103 | -- Michael Prokop Sat, 19 Oct 2024 17:23:30 +0200 104 | 105 | grml2usb (0.19.3) unstable; urgency=medium 106 | 107 | [ Michael Prokop ] 108 | * [5f40f1c] grml2usb docs: drop references to deprecated grml-medium 109 | 110 | [ Chris Hofstaedtler ] 111 | * [418f5db] Add GitHub Actions workflow to build grml2usb.deb 112 | * [8c841fe] d/control: Capitalize Vcs-Git 113 | * [60f4229] d/control: Update my name 114 | * [ca3f02c] d/control: set Rules-Requires-Root: no 115 | * [8926abb] d/control: uppercase USB in description 116 | 117 | -- Michael Prokop Fri, 06 Sep 2024 17:39:48 +0200 118 | 119 | grml2usb (0.19.2) unstable; urgency=medium 120 | 121 | * [2955aaf] codecheck: reformat with black, version 23.1.0 122 | (Closes: #1031466) 123 | 124 | -- Michael Prokop Mon, 20 Feb 2023 11:33:34 +0100 125 | 126 | grml2usb (0.19.1) unstable; urgency=medium 127 | 128 | * [27eba4a] Replace egrep usage with grep -E 129 | * [ec28a50] Bump Standards-Version to 4.6.2 130 | 131 | -- Michael Prokop Wed, 08 Feb 2023 08:27:50 +0100 132 | 133 | grml2usb (0.19.0) unstable; urgency=medium 134 | 135 | [ Manuel Rom ] 136 | * [40221eb] Add Github action workflows for CI/CD 137 | 138 | [ Michael Prokop ] 139 | * [3f77679] Fix vulture usage and add vulture to Build-Depends 140 | * [a6cce22] Github action: do not install virtualenv + 141 | python3-setuptools. Thanks to Chris Hofstaedtler 142 | * [78ae858] grml2iso: support parallel execution 143 | * [8126bbf] grml2iso: execute under pipefail 144 | 145 | -- Michael Prokop Mon, 21 Mar 2022 16:19:54 +0100 146 | 147 | grml2usb (0.18.5) unstable; urgency=medium 148 | 149 | * [01ed11d] Fix --grub and --syslinux handling. Thanks to Ralf Moll for 150 | the bugreport 151 | 152 | -- Michael Prokop Fri, 22 Jan 2021 10:32:43 +0100 153 | 154 | grml2usb (0.18.4) unstable; urgency=medium 155 | 156 | [ Michael Prokop ] 157 | * [3664e4a] Code cleanups. Thanks to Chris Hofstaedtler for review + 158 | feedback 159 | * [1dfee7d] Use "GRML" as FAT label when creating the file system 160 | * [272b66e] Fix race condition with blockdev/BLKRRPART due to lack of 161 | fsync. Thanks to dann frazier for bug report and 162 | patch (Closes: #975015) 163 | * [100a957] Bump Standards-Version to 4.5.1 164 | 165 | [ Darshaka Pathirana ] 166 | * [7656c18] Use consistent case of 'USB' and 'Grml' 167 | 168 | [ Manuel Rom ] 169 | * [6f3eb52] Add unit testing capabilities and basic tests for 170 | check_for_usbdevice 171 | 172 | -- Michael Prokop Fri, 27 Nov 2020 17:56:02 +0100 173 | 174 | grml2usb (0.18.3) unstable; urgency=medium 175 | 176 | * [9e7dd96] codecheck: fix flake8 issues with versions >=3.8.3. Thanks 177 | to Florian Apolloner for feedback (Closes: #963454) 178 | * [ec5eec1] setup.cfg: adjust flake8 section so invoking it without 179 | arguments works. Thanks to Florian Apolloner 180 | * [92ffc08] Support Grml's new Secure Boot approach 181 | * [b1798d1] Do not fail if ISO doesn't have grub.cfg inside efi.img 182 | * [f052436] grml2iso: switch from isohybrid to xorriso/isohybrid to 183 | properly support EFI boot 184 | * [9b96f21] docs: drop no longer needed strong->bold workaround from 185 | asciidoc/xsltproc toolchain 186 | * [ded5534] docs: rework grml2iso docs, including note about order of 187 | ISOs 188 | 189 | -- Michael Prokop Wed, 24 Jun 2020 11:27:28 +0200 190 | 191 | grml2usb (0.18.2) unstable; urgency=medium 192 | 193 | * [657b880] Skip boot flag check when installing to directory 194 | 195 | -- Michael Prokop Sat, 06 Jun 2020 15:09:37 +0200 196 | 197 | grml2usb (0.18.1) unstable; urgency=medium 198 | 199 | [ Michael Prokop ] 200 | * [705a96b] Drop old bootflag detection + be more verbose about its 201 | execution. Thanks to Darshaka Pathirana for bug report and debugging 202 | * [aed7d83] Use "boot flag" instead of "bootflag" also in docs + 203 | exceptions 204 | * [fcf63b7] Reread partition table after installing MBR to ensure 205 | devices exist. Thanks to Darshaka Pathirana for debugging 206 | 207 | [ Darshaka Pathirana ] 208 | * [8b59cb0] Check for boot flag before possibly creating FAT16 on the 209 | partition 210 | 211 | -- Michael Prokop Wed, 03 Jun 2020 16:55:00 +0200 212 | 213 | grml2usb (0.18.0) unstable; urgency=medium 214 | 215 | [ Tomáš Virtus ] 216 | * [25c3bf7] Fix Python 3 syntax warning (is vs ==) 217 | * [ed5b633] Support more Syslinux module locations 218 | * [f0e3c93] Fix duplicate Syslinux entries 219 | * [99ecee2] Add mbr/ output files to gitignore 220 | * [480b974] Fix duplicate Syslinux entries (2) 221 | 222 | [ Alexei Colin ] 223 | * [4d81cdb] tarball.sh: spaces in pattern for PROG_VERSION 224 | 225 | [ Michael Prokop ] 226 | * [d01d9d8] Coding style: fix pep8 + flake8 issues 227 | * [b188002] Coding style: execute black + isort and fix undefined 'path' 228 | * [f1d1ce8] codecheck: rely on flake8, isort + black during build time. 229 | Thanks to Florian Apolloner for the feedback 230 | * [31853ed] Bump Standards-Version to 4.5.0 231 | * [c921dc1] debian: execute `wrap-and-sort -a -t -s` 232 | * [1fa8aac] autopkgtests: drop python2 support and depend on python3 233 | only (Closes: #936663) 234 | * [aaaef1a] debian: switch to debhelper minimal style 235 | * [263374b] Get rid of docbook-xsl workaround regarding duplicate empty 236 | lines 237 | 238 | -- Michael Prokop Tue, 12 May 2020 17:16:34 +0200 239 | 240 | grml2usb (0.17.0) unstable; urgency=medium 241 | 242 | [ Sven Joachim ] 243 | * [5b2ffe4] check_for_fat: Avoid comparing strings and bytes (Closes: #943838) 244 | * [c2e742a] check_boot_flag(): Open device in binary mode 245 | * [fd89485] Fix path to syslinux *.c32 files (Closes: #943845) 246 | 247 | 248 | [ Michael Prokop ] 249 | * [4d800e5] Provide git-describe based version information when running 250 | from within git. Thanks to Florian Apolloner for review and feedback 251 | * [9586781] No longer explicitly list addon files, instead copy all 252 | files from /boot/addons/ 253 | * [ea3de89] check_for_fat(): use subprocess.check_output to avoid 254 | dependency on Python 3.7. Thanks to Florian Apolloner for review and 255 | feedback 256 | 257 | -- Michael Prokop Thu, 31 Oct 2019 12:00:01 +0100 258 | 259 | grml2usb (0.16.7) unstable; urgency=medium 260 | 261 | [ Chris Hofstaedtler ] 262 | * [d3008fb] grml2usb: abort if required logo.16 file is missing 263 | * [6c16c88] grml2usb: print backtrace when --verbose is given 264 | * [3fd61a4] grml2usb: Add smoke autopkgtest for python2 265 | * [b2b68f0] grml2usb: add python3 test variant 266 | 267 | [ Michael Prokop ] 268 | * [66679fa] Port to py3k (Closes: #936663) 269 | * [29d54d4] Avoid subprocess.Popen with stdout/stderr=PIPE and wait() 270 | usage 271 | * [aaf46a1] Bump Standards-Version to 4.4.1 272 | * [0721603] Drop debian/compat and switch to debhelper-compat instead 273 | 274 | -- Michael Prokop Tue, 22 Oct 2019 15:18:23 +0200 275 | 276 | grml2usb (0.16.6) unstable; urgency=medium 277 | 278 | * [ef2f28e] Avoid custom boot options getting duplicated when used with 279 | multiple ISOs. Thanks to Ralf Moll for the bug report and Lukas Prokop 280 | for providing the bug fix 281 | 282 | -- Michael Prokop Thu, 11 Jul 2019 17:26:16 +0200 283 | 284 | grml2usb (0.16.5) unstable; urgency=medium 285 | 286 | * [95b0773] Switch default mount point from /lib/live/mount/medium to 287 | /run/live/medium 288 | 289 | -- Michael Prokop Thu, 21 Mar 2019 12:23:59 +0100 290 | 291 | grml2usb (0.16.4) unstable; urgency=medium 292 | 293 | * [203ce99] Force usage with python2 (Closes: #921327) 294 | * [c27e1e2] docs: update ISO filenames, referring to a more recent 295 | stable version 296 | * [a31bc9e] Update copyright year information 297 | * [ba5ec1e] grml2iso: update ISO filename in usage example 298 | 299 | -- Michael Prokop Thu, 28 Feb 2019 16:02:40 +0100 300 | 301 | grml2usb (0.16.3) unstable; urgency=medium 302 | 303 | * [1d43bf3] Bump Standards-Version to 4.3.0 304 | * [daaf329] Depend on either syslinux or grub2-common + grub-pc-bin. 305 | Thanks to Albert Dengg for bugreport and suggested solution + Axel 306 | Beckert for assistance in getting a proper dependency resolution 307 | (Closes: #796801) 308 | * [ae4c051] No longer depend on coreutils or realpath. Thanks to Michael 309 | Stone for the bug report (Closes: #877554) 310 | 311 | -- Michael Prokop Wed, 20 Feb 2019 16:35:12 +0100 312 | 313 | grml2usb (0.16.2) unstable; urgency=medium 314 | 315 | [ joeran ] 316 | * [92d09d8] Python3: Some improvements to increase support 317 | 318 | [ Michael Prokop ] 319 | * [e4f812a] Make recent versions of pep8 happy 320 | * [1e9487b] Bump Standards-Version to 4.2.1 321 | * [d54dd34] Switch Homepage header from http to https 322 | 323 | -- Michael Prokop Thu, 15 Nov 2018 10:01:30 +0100 324 | 325 | grml2usb (0.16.1) unstable; urgency=medium 326 | 327 | * [7ca80ac] Fix a bunch of typos 328 | * [5e37e24] Bump Standards-Version to 4.1.4 329 | 330 | -- Michael Prokop Fri, 25 May 2018 13:54:59 +0200 331 | 332 | grml2usb (0.16.0) unstable; urgency=medium 333 | 334 | * [70c9de3] Provide Secure Boot support 335 | 336 | -- Michael Prokop Thu, 07 Sep 2017 09:40:59 +0200 337 | 338 | grml2usb (0.15.4) unstable; urgency=medium 339 | 340 | * [976735f] Bump Standards-Version to 4.0.1 341 | * Upload to Debian unstable now that stretch is stable. 342 | 343 | -- Michael Prokop Thu, 17 Aug 2017 14:50:03 +0200 344 | 345 | grml2usb (0.15.3) experimental; urgency=medium 346 | 347 | * [9cbb231] Option --rw-blockdev: set r/w also in GRUB specific steps. 348 | Thanks to Ralf Moll 349 | * [6412ea2] Ensure that grub-install doesn't receive emtpy command line 350 | argument 351 | 352 | -- Michael Prokop Wed, 31 May 2017 11:28:43 +0200 353 | 354 | grml2usb (0.15.2) experimental; urgency=medium 355 | 356 | * [2ce7572] Support netboot.xyz.lkrn addon. Thanks to Michael Schierl 357 | for reporting the bug 358 | 359 | -- Michael Prokop Fri, 26 May 2017 23:34:40 +0200 360 | 361 | grml2usb (0.15.1) experimental; urgency=medium 362 | 363 | * [e4a7747] Don't fail hard if installing on partition number >4, 364 | instead warn user [Closes: issue1353] 365 | * [4630689] Option --rw-blockdev: ensure to set device to rw between 366 | grub-install runs + don't set rw on source 367 | 368 | -- Michael Prokop Wed, 24 May 2017 15:47:54 +0200 369 | 370 | grml2usb (0.15.0) experimental; urgency=medium 371 | 372 | The "¡Hola Alicante!" release 373 | 374 | * [5033f52] Support --rw-blockdev option for usage with read- 375 | only/forensic like devices 376 | 377 | -- Michael Prokop Thu, 27 Apr 2017 18:48:28 +0200 378 | 379 | grml2usb (0.14.14) unstable; urgency=medium 380 | 381 | [ Michael Prokop ] 382 | * [97f73b0] Coding style fixes to make pep8 happy 383 | 384 | [ Christian Hofstaedtler ] 385 | * [0d13a49] Update my email address 386 | * [019a392] Bump Standards-Version to 3.9.8 (no changes needed) 387 | * [a6996e9] Bump debhelper compat level to 10 388 | * [45e16e7] Use https URL in Vcs-Browser 389 | * [b400d9c] Correct duplicate word in previous changelog entry 390 | 391 | -- Michael Prokop Tue, 24 Jan 2017 21:47:41 +0100 392 | 393 | grml2usb (0.14.13) unstable; urgency=medium 394 | 395 | [ Evgeni Golov ] 396 | * [745f097] Catch parted returning None as the searched partition. 397 | Thanks to mika and Haudegen for debugging (Closes: #766964) 398 | 399 | -- Michael Prokop Mon, 28 Sep 2015 18:18:14 +0200 400 | 401 | grml2usb (0.14.12) unstable; urgency=medium 402 | 403 | [ Lukas Prokop ] 404 | * [a3065b8] Fix typo 405 | 406 | [ Michael Prokop ] 407 | * [6274d13] Realpath is provided by recent coreutils versions, adjust 408 | Depends. Thanks to Ben Finney for 409 | reporting (Closes: #780948) 410 | 411 | -- Michael Prokop Sat, 06 Jun 2015 01:41:57 +0200 412 | 413 | grml2usb (0.14.11) experimental; urgency=medium 414 | 415 | [ Lukas Prokop ] 416 | * [4a2ffdd] Introduce skip-usb-check 417 | * [6868425] Disable usage of --copy-only and --grub at the same time 418 | 419 | [ Michael Prokop ] 420 | * [fa02a2b] Display information when using --skip-usb-check options 421 | * [1fe44d6] Adjust sorting of cmdline options 422 | * [7a6e10d] Sync filesystems before returning from MBR installation 423 | (Closes: #779193) 424 | * [371c60e] Add syslinux-utils to Recommends + adjust error message for 425 | isohybrid 426 | * [a3dde41] Support usage of grml2usb on EFI systems (Closes: #768906) 427 | * [4a8972f] Document --skip-usb-check option 428 | 429 | -- Michael Prokop Thu, 26 Feb 2015 14:34:59 +0100 430 | 431 | grml2usb (0.14.10) unstable; urgency=medium 432 | 433 | [ Michael Prokop ] 434 | * [3b84e56] Document --skip-bootflag cmdline option 435 | 436 | [ Evgeni Golov ] 437 | * [018de7b] Fix "global name 'parted' is not defined" error in grml2usb 438 | 439 | -- Michael Prokop Mon, 13 Oct 2014 10:52:21 +0200 440 | 441 | grml2usb (0.14.9) unstable; urgency=medium 442 | 443 | * [2b2c97a] Use pyparted to check for bootflag 444 | [Closes: issue1248] [Closes: #757993] 445 | Thanks to Evgeni Golov for further 446 | improving my initial patch. 447 | 448 | -- Michael Prokop Tue, 07 Oct 2014 08:43:38 +0200 449 | 450 | grml2usb (0.14.8) unstable; urgency=medium 451 | 452 | [ Florian Apolloner ] 453 | * [f993114] style fixes 454 | 455 | [ joeran ] 456 | * [2b664f3] Extend search paths for syslinux MBRs 457 | 458 | [ Michael Prokop ] 459 | * [a64597b] Bump Standards-Version to 3.9.6 460 | 461 | -- Michael Prokop Thu, 02 Oct 2014 11:47:12 +0200 462 | 463 | grml2usb (0.14.7) unstable; urgency=medium 464 | 465 | * [1cb2e6a] Execute wrap-and-sort on debian directory 466 | * [09300f0] Fix usage of grub-install command. Thanks to martin f krafft 467 | for spotting the problem (Closes: #755768) 468 | 469 | -- Michael Prokop Mon, 11 Aug 2014 22:09:27 +0200 470 | 471 | grml2usb (0.14.6) unstable; urgency=medium 472 | 473 | * [f434e19] Add support for Python 3 474 | 475 | -- Michael Prokop Fri, 04 Jul 2014 10:08:26 +0200 476 | 477 | grml2usb (0.14.5) unstable; urgency=medium 478 | 479 | [ Andreas "Jimmy" Gredler ] 480 | * [178c7f0] Fixed manpages 481 | * [b214ea0] Minor change in manpage 482 | * [efd19d8] Replaced all occurences of grml with Grml in the manpages 483 | * [3176494] Replaced all occurences of iso or Iso with ISO(s) in the 484 | manpages 485 | 486 | [ Daniel Troeder ] 487 | * [5b3b5f7] allow grub-install to be called grub2-install (used in 488 | gentoo) 489 | 490 | [ Michael Prokop ] 491 | * [22a2cd3] docs: fix typo (persisten*t*-path and wrong uppercase usage 492 | of Grml64/Grml in syslinux) 493 | 494 | -- Michael Prokop Thu, 03 Jul 2014 12:48:16 +0200 495 | 496 | grml2usb (0.14.4) unstable; urgency=medium 497 | 498 | [ Lukas Prokop ] 499 | * [4be3d88] Ask user whether he really wants to use non-grml folder 500 | * [2b2bf9e] Adverb is actually adjective. 501 | * [411daf1] Silence errors the right way. 502 | * [2700dd6] Implement folder cleanup support for TMPFILES 503 | (Closes github issue #5) 504 | * [1d3c9da] Provide log message for umounted device in cleanup() 505 | * [b2b4887] Create copies of set before iteration 506 | * [d33e012] Silent error for StandardError, not RuntimeError 507 | 508 | [ Michael Prokop ] 509 | * [e2a98b2] More consequently use "Grml" instead of "grml" 510 | 511 | -- Michael Prokop Mon, 24 Feb 2014 16:02:11 +0100 512 | 513 | grml2usb (0.14.3) unstable; urgency=medium 514 | 515 | * [dbf34c4] Bump Standards-Version to 3.9.5 516 | * [6bf0be8] Fix logic of isohybrid execution if uefi option is not 517 | supported 518 | 519 | -- Michael Prokop Fri, 07 Feb 2014 18:38:25 +0100 520 | 521 | grml2usb (0.14.2) unstable; urgency=low 522 | 523 | [ Michael Prokop ] 524 | * [bb87234] pep8 cleanups 525 | * [1d2aba6] Fix typo in /boot/grub/addons.cfg filename. Thanks to 526 | Michael Schierl for the hint 527 | 528 | [ Christian Hofstaedtler ] 529 | * [be8270f] Remove Recommends: isolinux, as the package is gone 530 | 531 | -- Michael Prokop Thu, 31 Oct 2013 08:45:06 +0100 532 | 533 | grml2usb (0.14.1) unstable; urgency=low 534 | 535 | [ Till Maas ] 536 | * [d26c252] Support also /usr/share/syslinux/ to look for mbr.bin 537 | 538 | -- Michael Prokop Wed, 14 Aug 2013 13:04:40 +0200 539 | 540 | grml2usb (0.14.0) unstable; urgency=low 541 | 542 | * [360c9e5] Use lowercase 'timeout' command in syslinux configuration 543 | [Closes: issue1262] Thanks to Martin Šlouf for reporting this bug 544 | including a workaround 545 | * grml2iso related changes: 546 | - [20752e3] skip --uefi option of isohybrid if ISO doesn't 547 | ship /boot/efi.img 548 | - [f3370b9] extend error message of required ISO generation 549 | tools with xorriso 550 | - [8e0bdf8] mention isolinux in 'isohybrid executable not 551 | found' message, add isolinux to recommends 552 | - [37fa9f8] disable UEFI mode by default, only enable for 553 | xorriso under according prerequisites 554 | - [86c00b8] make sure we have the sbin directories in our PATH 555 | 556 | -- Michael Prokop Wed, 26 Jun 2013 17:27:18 +0200 557 | 558 | grml2usb (0.13.8) unstable; urgency=low 559 | 560 | * [de40a5f] Skip check for bootflag if a GPT header is present 561 | 562 | -- Michael Prokop Wed, 15 May 2013 14:54:21 +0200 563 | 564 | grml2usb (0.13.7) unstable; urgency=low 565 | 566 | The "towards jessie" release 567 | 568 | [ Christian Hofstaedtler ] 569 | * [87143a6] Remove obsolete DM-Upload-Allowed flag 570 | 571 | [ Evgeni Golov ] 572 | * [3fb00de] "if not" also triggers when value is 0, use 573 | "if is None" instead 574 | 575 | [ Lukas Prokop ] 576 | * [7b409af] Fix typo. 577 | * Rework error handling to avoid unnecessary backtraces, 578 | commmits [26cf633] [7cef744] [6990c85] [5276a23] [cdb4aa4] 579 | [a06f95e] and [fafa0d8] 580 | 581 | -- Michael Prokop Tue, 14 May 2013 19:04:50 +0200 582 | 583 | grml2usb (0.13.6) experimental; urgency=low 584 | 585 | * [9e7a48d] grml2iso: make sure to exit properly if provided argument to 586 | -c option does not exist 587 | * [a22cf21] Make sure modprobe executable can be accessed 588 | * [62acdab] grml2iso: provide more user-friendly error message if 589 | grml2usb executable is not available 590 | * [0ab2a72] Normalize temporary working directory to not fail with 591 | relative directory path 592 | 593 | -- Michael Prokop Tue, 23 Apr 2013 22:32:36 +0200 594 | 595 | grml2usb (0.13.5) experimental; urgency=low 596 | 597 | [ Evgeni Golov ] 598 | * [a17807b] fix detection of strange (xxxNpM) structures when finding 599 | the device for a partition [Closes: issue1244] 600 | 601 | -- Michael Prokop Mon, 18 Mar 2013 15:12:10 +0100 602 | 603 | grml2usb (0.13.4) experimental; urgency=low 604 | 605 | * [aff3fa9] Add realpath to Depends as it's required by grml2iso 606 | * [14e017c] Do not use partition for bootflag check but disk itself 607 | * [0deeae3] Mention /lib/live/mount/medium for new live path + adjust 608 | ISO versions 609 | 610 | -- Michael Prokop Thu, 10 Jan 2013 14:08:09 +0100 611 | 612 | grml2usb (0.13.3) experimental; urgency=low 613 | 614 | * [7705455] grml2iso: use absolute path for working directory to not 615 | fail when user specified relative path 616 | * [3f80e5a] Verify that the bootflag is enabled 617 | * [922c039] Bump Standards-Version to 3.9.4 618 | 619 | -- Michael Prokop Mon, 17 Dec 2012 13:21:39 +0100 620 | 621 | grml2usb (0.13.2) unstable; urgency=low 622 | 623 | [ Michael Prokop ] 624 | * [7e6faf1] Fix logging message if operating on a directory 625 | * [cf525c6] Exit with better error message if running with toram=... and 626 | invoking with /live/image 627 | 628 | [ Lukas Prokop ] 629 | * [5251ce1] Fix error message. 630 | 631 | -- Michael Prokop Tue, 11 Sep 2012 18:28:31 +0200 632 | 633 | grml2usb (0.13.1) unstable; urgency=low 634 | 635 | * [720b859] grml2iso: make ISOs dd-able through isohybrid 636 | 637 | -- Michael Prokop Tue, 11 Sep 2012 12:16:04 +0200 638 | 639 | grml2usb (0.13.0) unstable; urgency=low 640 | 641 | [ Michael Prokop ] 642 | * [927e586] grml2iso: fix typo + improve wording 643 | * [178cb6a] grml2iso: support -t to set temporary working directory 644 | 645 | [ Lukas Prokop ] 646 | * [752b503] grml2usb: introduce option --tmpdir 647 | 648 | -- Michael Prokop Mon, 10 Sep 2012 09:13:25 +0200 649 | 650 | grml2usb (0.12.2) unstable; urgency=low 651 | 652 | * [f3a85ac] copy_addons: install all *.c32 addons in /boot/addons/ 653 | (fixing broken addon entries in grml96 ISOs) 654 | 655 | -- Michael Prokop Mon, 28 May 2012 17:16:40 +0200 656 | 657 | grml2usb (0.12.1) unstable; urgency=low 658 | 659 | * [7c076d1] Support multiple flavours inside one ISO. Thanks to Ulrich 660 | Dangel for the patch (Closes: issue1172) 661 | 662 | -- Michael Prokop Sun, 27 May 2012 22:23:07 +0200 663 | 664 | grml2usb (0.12.0) unstable; urgency=low 665 | 666 | [ Michael Prokop ] 667 | * [f1cfc39] grml2iso: use shell for calculation instead of using bc 668 | * [2223843] Rebuild loopback.cfg with present configuration files 669 | * [5df5aeb] Bump Standards-Version to 3.9.3 670 | * [09149d7] Drop oudated tarball-online make target and support 671 | prepare-release instead 672 | * [607fd41] pep8 cleanups 673 | * [c2d87f6] Adjust PROG_VERSION code in debian/rules for pep8 cleanup 674 | 675 | [ Evgeni Golov ] 676 | * [3505897] fix manpage markup 677 | 678 | -- Michael Prokop Wed, 09 May 2012 12:58:46 +0200 679 | 680 | grml2usb (0.11.6) unstable; urgency=low 681 | 682 | The "custom bootsplash without remastering ☕☕☕" release 683 | 684 | [ Ulrich Dangel ] 685 | * [f956c82] grml2iso: Canonicalize overlay directory 686 | * [7494e3f] grml2iso: Support template parameters in overlay directory. 687 | For now only GRML_NAME, VERSION, RELEASENAME, DATE, SHORT_NAME, 688 | RELEASE_INFO and BOOTID are supported. 689 | 690 | -- Michael Prokop Fri, 27 Jan 2012 12:29:21 +0100 691 | 692 | grml2usb (0.11.5) unstable; urgency=low 693 | 694 | The "grml96 support ♫♫♫" release 695 | 696 | [ Ulrich Dangel ] 697 | * [eb087c0] Support multiple flavours on a cd 698 | * [4608131] Modify grub config files for the specified flavour instead 699 | of all grub config files 700 | * [c6af951] Streamline grml_flavour modification 701 | * [c421fb3] Only modify live-media-path for current flavour 702 | 703 | -- Michael Prokop Wed, 11 Jan 2012 16:10:51 +0100 704 | 705 | grml2usb (0.11.4) unstable; urgency=low 706 | 707 | [ Ulrich Dangel ] 708 | * [35feaad] Copy complete Grml flavour directory instead of explicit 709 | specifying files 710 | 711 | [ Michael Prokop ] 712 | * [7c0195d] Make sure we don't fail in device check when using 713 | /dev/disk-by-label/* - Thanks to Bernhard Tittelbach 714 | 715 | -- Michael Prokop Mon, 09 Jan 2012 16:37:18 +0100 716 | 717 | grml2usb (0.11.3) unstable; urgency=low 718 | 719 | [ Christian Hofstaedtler ] 720 | * [894eef9] Use grub splash image from ISO 721 | * [fdc186c] Remove hardcoded version from grml2usb 722 | * [bd89fc4] Cleanup grub.cfg install logic 723 | * [569dfb3] Add support for new kernel/initrd filenames 724 | * [5818eec] Fix add/remove bootoptions with new kernel/initrd names 725 | * [6817350] Fix typo 726 | * [b82aaee] Mimic /boot/%SHORT_NAME% like on the ISO 727 | * [100193b] Use grub config from ISO instead of writing a new one 728 | * [feca364] Warn that older versions can't do multi-flavour grub 729 | * [6b93ccd] Load loop kernel module [Closes: issue1097] 730 | 731 | -- Michael Prokop Thu, 22 Dec 2011 23:55:08 +0100 732 | 733 | grml2usb (0.11.2) unstable; urgency=low 734 | 735 | [ Christian Hofstaedtler ] 736 | * [bd2f924] Remove 'quiet' from standard boot options 737 | * [4f47c04] Remove failsafe boot menu entry 738 | 739 | [ Michael Prokop ] 740 | * [a1ca17b] Add UEFI boot support to grml2iso 741 | 742 | -- Michael Prokop Thu, 15 Dec 2011 14:35:58 +0100 743 | 744 | grml2usb (0.11.1) unstable; urgency=low 745 | 746 | [ Christian Hofstaedtler ] 747 | * [2534968] Add nokms option to grub menu 748 | * [e9f7cff] sync grub.cfg menu entries with grml-live templates 749 | 750 | -- Michael Prokop Sun, 11 Dec 2011 21:28:12 +0100 751 | 752 | grml2usb (0.11.0) unstable; urgency=low 753 | 754 | * [b1bf09c] Install boot files required for [U]EFI boot 755 | 756 | -- Michael Prokop Thu, 08 Dec 2011 15:00:04 +0100 757 | 758 | grml2usb (0.10.2) unstable; urgency=low 759 | 760 | [ Christian Hofstaedtler ] 761 | * [8483753] Remove mention of grml2hd 762 | * [49672e8] Disable validation of autogenerated docbook xml 763 | 764 | -- Michael Prokop Sat, 26 Nov 2011 20:30:20 +0100 765 | 766 | grml2usb (0.10.1) unstable; urgency=low 767 | 768 | Packaging fixes: 769 | * [05f4996] Fix FTBFS on i386: must build arch package in binary-arch 770 | * [ba108d8] Reword/reformat some text in debian/copyright 771 | 772 | -- Christian Hofstaedtler Tue, 04 Oct 2011 10:07:42 +0200 773 | 774 | grml2usb (0.10.0) unstable; urgency=low 775 | 776 | Target Debian unstable: 777 | * Build only on i386 and amd64. 778 | * Remove Grml Origin and Bugs entries 779 | 780 | -- Christian Hofstaedtler Mon, 03 Oct 2011 23:27:14 +0200 781 | 782 | grml2usb (0.9.35) unstable; urgency=low 783 | 784 | * [19b2fe7] Support USB keys with superfloppy format 785 | * [e8fb17b] grml2iso: fix check for grml2usb 786 | * [e1ad166] Loop-mount ISO with read-only option 787 | * [e5ae97f] Remove grml2usb-compat 788 | * [5d028a0] Remove grub1 support 789 | * [7874f97] Remove static lilo binaries and lilo support 790 | 791 | Packaging changes: 792 | * [ecfce70] Use dh_prep, bump debhelper compat level to 7 793 | * [1b22f2a] Set debian/source/format to 3.0 (native) 794 | * [7a142d9] Fix debian-rules-missing-recommended-target lintian warning 795 | * [c26aae4] No longer mention mkisofs in debian/control 796 | * [fdb81b1] Add debian/control headers Origin, Bugs 797 | * [154f7d7] Switch section to admin, from grml 798 | * [7e48792] Update Maintainer/Uploaders to Team 799 | 800 | -- Christian Hofstaedtler Mon, 03 Oct 2011 23:06:42 +0200 801 | 802 | grml2usb (0.9.34) unstable; urgency=low 803 | 804 | * [def6424] Fix warning message for missing files. 805 | 806 | -- Michael Prokop Fri, 22 Jul 2011 09:41:24 +0200 807 | 808 | grml2usb (0.9.33) unstable; urgency=low 809 | 810 | * [c021230] Don't nag users about gpxe.lkrn 811 | 812 | -- Christian Hofstaedtler Mon, 16 May 2011 00:49:34 +0200 813 | 814 | grml2usb (0.9.32) unstable; urgency=low 815 | 816 | [ Michael Prokop ] 817 | * [b2a896e] Support iPXE as new alternative for gPXE. 818 | * [a364513] Add pyflakes to codecheck. 819 | 820 | [ Christian Hofstaedtler ] 821 | * [c479a12] add an FAQ regarding to HDT hangs [Closes: issue976] 822 | * [39d0e12] Bump Standards-Version to 3.9.2 823 | * [af2a36f] Update debian/overrides for newer lintian versions 824 | 825 | -- Christian Hofstaedtler Tue, 10 May 2011 22:45:27 +0200 826 | 827 | grml2usb (0.9.31) unstable; urgency=low 828 | 829 | [ Ulrich Dangel ] 830 | * [f5e949b] Support mkisofs or genisoimage in grml2iso. Updated 831 | debian/control accordingly. 832 | * [a9ab0bf] Print warning if grml2usb is not found in grml2iso. 833 | * [d85b3e3] Support arbitrary grml2usb options in grml2iso. 834 | * [cc12ab6] Allow multiple --bootoptions for grml2usb. This makes 835 | scripting a lot easier. 836 | * [161f2d5] Support generating small iso images with grml2iso. 837 | 838 | [ Michael Prokop ] 839 | * [1980861] Typo fixes and minor formating corrections. 840 | 841 | -- Michael Prokop Mon, 14 Feb 2011 10:39:07 +0100 842 | 843 | grml2usb (0.9.30) unstable; urgency=low 844 | 845 | * [35b606b] fix broken grub command terminal_output (should be 846 | "terminal_output gfxterm" instead of terminal_output.gfxterm) - 847 | thanks to Bert Schulze 848 | 849 | -- Michael Prokop Sat, 08 Jan 2011 23:11:15 +0100 850 | 851 | grml2usb (0.9.29) unstable; urgency=low 852 | 853 | [ Thorsten Glaser ] 854 | * [601cc84] correct a pasto (it's 'grub.cfg') 855 | * [dc6a084] There is no /bin/bash on most operating systems. 856 | * [eb1a910] fix bsd4grml boot (loopback and regular) 857 | 858 | [ Ulrich Dangel ] 859 | * [3cec649] Append new flavours to grml-version, do not only update 860 | existing versions 861 | * [35d64cf] Update version 862 | * [ff5be86] Improve logging message 863 | 864 | [ Michael Prokop ] 865 | * [e32e549] Re-add mtools to Depends as they are just suggests of 866 | syslinux package - thanks to Michael Gissing for the bugreport. 867 | [Closes: issue905] 868 | 869 | -- Michael Prokop Thu, 25 Nov 2010 11:15:10 +0100 870 | 871 | grml2usb (0.9.28) unstable; urgency=low 872 | 873 | [ Ulrich Dangel ] 874 | * [7b4fa5c] Some code cleanup. 875 | * [2a93d92] Copy bootloader files from /usr/lib/syslinux/ 876 | [Closes: issue894] 877 | * [c0fd54e] Run grub-install without and with --force option. 878 | * [1a5a6cd] bsd4grml was not copied correctly to the target device. 879 | 880 | [ Christian Hofstaedtler ] 881 | * [875b62b] Rename variables in update_grml_versions to be less 882 | confusing. 883 | * [791485b] Properly update grml-versions when updating a grml 884 | flavour. 885 | 886 | [ Michael Prokop ] 887 | * [91529cc] Bump Standards-Version to 3.9.1. 888 | 889 | -- Michael Prokop Tue, 28 Sep 2010 23:57:16 +0200 890 | 891 | grml2usb (0.9.27) unstable; urgency=low 892 | 893 | [ Michael Prokop ] 894 | * [3836a71] Check for precense of grub/syslinux at startup time. 895 | Thanks to Eduard Bloch for reporting. [Closes: issue855] 896 | * [bde7012] Mention --force switch of grub-install in debug log. 897 | * [1c1c18c] Doc: fix documentation regarding default bootmanager. 898 | (thanks Martin Krafft). 899 | * [bae5bfb] Bump Standards-Version to 3.9.0. 900 | 901 | [ Ulrich Dangel ] 902 | * [b79a4cc] Fix error message for unintialized partition. 903 | [Closes: issue857] 904 | * [cd204ee] Fix user feedback about default flavour and 905 | installed flavours. 906 | 907 | -- Michael Prokop Wed, 30 Jun 2010 13:10:09 +0200 908 | 909 | grml2usb (0.9.26) unstable; urgency=low 910 | 911 | [ Ulrich Dangel ] 912 | * Code cleanup. 913 | * Support expanding bootoptions variables. 914 | * Fix string concatenation and string formatting error. 915 | 916 | [ Michael Prokop ] 917 | * Document grub option in manpage (thanks Andrey Rahmatulli). 918 | 919 | -- Michael Prokop Fri, 28 May 2010 01:16:35 +0200 920 | 921 | grml2usb (0.9.25) unstable; urgency=low 922 | 923 | * Fix typo in option handling. 924 | 925 | -- Michael Prokop Thu, 22 Apr 2010 18:10:35 +0200 926 | 927 | grml2usb (0.9.24) unstable; urgency=low 928 | 929 | [ Ulrich Dangel ] 930 | * Add support for isos containing multiple grml flavours. 931 | * Copy all {sys,iso}linux *.c32 files, like ifcpu64.c32. 932 | 933 | [ Michael Prokop ] 934 | * Use --force option for grub-install to support installation to PBR 935 | again. Grub2 starting with version 1.98 supports installation to 936 | PBR again iff using the --force option. 937 | * Update documentation regarding grub and PBR vs. MBR. 938 | 939 | -- Michael Prokop Wed, 21 Apr 2010 13:54:51 +0200 940 | 941 | grml2usb (0.9.23) unstable; urgency=low 942 | 943 | [ Ulrich Dangel ] 944 | * Only ask questions if options.force is not set. [Closes: issue833] 945 | 946 | -- Michael Prokop Fri, 02 Apr 2010 18:32:25 +0200 947 | 948 | grml2usb (0.9.22) unstable; urgency=low 949 | 950 | [ Ulrich Dangel ] 951 | * Use GRML_{FLAVOURS,DEFAULT}, PROG_VERSION from global scope. 952 | grml2usb was aborted when using --bootloader-only --skip-grub-config 953 | as parameters. This fixes the behaviour and declares correctly the 954 | correct scope for these variables. Thanks to Daniel Tiefnig for 955 | reporting the bug. 956 | 957 | [ Michael Prokop ] 958 | * grml2usb-compat: drop duplicated boot=live bootoptions. 959 | * Bump Standards-Version to 3.8.4 (no further changes). 960 | * Add syslinux additionally to recommends so people should have 961 | syslinux by available by default though don't explicitly require it. 962 | 963 | -- Michael Prokop Sun, 21 Feb 2010 16:52:23 +0100 964 | 965 | grml2usb (0.9.21) unstable; urgency=low 966 | 967 | [ Michael Prokop ] 968 | * Document the Boot error issue regarding USB-ZIP. 969 | 970 | [ Ulrich Dangel ] 971 | * Support bootid bootoption. 972 | 973 | -- Michael Prokop Thu, 04 Feb 2010 00:56:56 +0100 974 | 975 | grml2usb (0.9.20) unstable; urgency=low 976 | 977 | * tarball.sh: do not use $UID but use $(id -u) instead so it proberly 978 | works with dash and make sure to escape "$0". Thanks to Stefan Weiss! 979 | 980 | -- Michael Prokop Wed, 25 Nov 2009 00:47:36 +0100 981 | 982 | grml2usb (0.9.19) unstable; urgency=low 983 | 984 | [ Ulrich Dangel ] 985 | * check_for_fat always check for fat device. 986 | * Unset option.syslinux if grub option is set. 987 | * Mount vfat devices with explicit iocharset option. 988 | [Closes: issue735] 989 | 990 | -- Michael Prokop Wed, 11 Nov 2009 18:34:56 +0100 991 | 992 | grml2usb (0.9.18) unstable; urgency=low 993 | 994 | [ Ulrich Dangel ] 995 | * Also set GRML_DEFAULT when running with --dry-run. Thanks to Moritz 996 | Augsburger for the bug report. 997 | * Make sure that --grub-mbr requires --grub. Thanks to Moritz 998 | Augsburger and mika for the bug report. 999 | 1000 | -- Michael Prokop Wed, 04 Nov 2009 20:51:24 +0100 1001 | 1002 | grml2usb (0.9.17) unstable; urgency=low 1003 | 1004 | [ Michael Prokop ] 1005 | * Depend on rsync (thanks for the bugreport, Andras Korn). 1006 | 1007 | [ Ulrich Dangel ] 1008 | * Adjust labels in {grml,default}.cfg if necessary. 1009 | * Always copy grub files. 1010 | 1011 | -- Michael Prokop Thu, 29 Oct 2009 01:06:12 +0100 1012 | 1013 | grml2usb (0.9.16) unstable; urgency=low 1014 | 1015 | * Dynamic check for addons as grml-small is nowadays shipped with addons. 1016 | * Copy gpxe.lkrn from addons. 1017 | * Modified grml2usb to be able to run on a generated grml2usb iso/directory. 1018 | 1019 | -- Ulrich Dangel Tue, 27 Oct 2009 21:41:07 +0100 1020 | 1021 | grml2usb (0.9.15) unstable; urgency=low 1022 | 1023 | * Support new addon menu file layout from grml-live. 1024 | 1025 | -- Ulrich Dangel Mon, 26 Oct 2009 12:32:27 +0100 1026 | 1027 | grml2usb (0.9.14) unstable; urgency=low 1028 | 1029 | [ Ulrich Dangel ] 1030 | * Do not use '-' in the directory name for the linux kernel to allow 1031 | creating iso image from generated directory layout. 1032 | * Introduced --remove-bootoption in grml2usb to delete existing 1033 | default boot entries. 1034 | * Added -c option to grml2iso for copying the contents of specified 1035 | directory to the generated iso image. 1036 | * Added -b option to grml2iso for specifying additional default 1037 | boot entries. 1038 | 1039 | [ Michael Prokop ] 1040 | * Sync and add grml2usb-compat to grml2usb package. This simplifies 1041 | installation as well as use for developers and users. 1042 | * Drop unnecessary header line from grml2usb script. 1043 | 1044 | -- Michael Prokop Sat, 24 Oct 2009 14:29:46 +0200 1045 | 1046 | grml2usb (0.9.13) unstable; urgency=low 1047 | 1048 | [ Ulrich Dangel ] 1049 | * Modified syslinux configuration handling to generate new vesa 1050 | menu entries. 1051 | * Support adding additional isos to existing grml2usb installation. 1052 | * grml2iso supports new grml2usb using syslinux now. 1053 | 1054 | [ Michael Prokop ] 1055 | * Update documentation regarding syslinux and FAT32 (thanks to 1056 | Stefan Traby for the hint). 1057 | * Changes with regards to Ulrich's work: 1058 | - Add a check to identify old ISOs which do not ship 1059 | a default.cfg file and abort then. We have to break 1060 | backward compatibility, otherwise the isolinux/syslinux 1061 | code would become worse than it's already nowadays. 1062 | - Search for isolinux files in /boot/isolinux/ so the 1063 | correct grml.png is used. 1064 | - Support setting bootoptions in syslinux.cfg 1065 | * Drop duplicated boot=live references in kernel cmdline. 1066 | * Apply patch from Thorsten Glaser which prepares code for 1067 | his future[tm] work. 1068 | * Raise CriticalException if filesystem.module, kernel or 1069 | initrd are not present. 1070 | * Avoid the "file is read only, overwrite anyway (y/n) ?" 1071 | question of mtools by syslinux. 1072 | * Inform user when using grub as bootloader. 1073 | * Make syslinux the default bootloader (drop --syslinux, 1074 | add --grub instead). Grub fails just too often. 1075 | 1076 | -- Michael Prokop Wed, 21 Oct 2009 22:25:57 +0200 1077 | 1078 | grml2usb (0.9.12) unstable; urgency=low 1079 | 1080 | * Replace 'logging.*("%s" % foo)' with 'logging.*("%s", foo)' 1081 | so the logging works with python2.6 as well. 1082 | 1083 | -- Michael Prokop Thu, 10 Sep 2009 16:21:06 +0200 1084 | 1085 | grml2usb (0.9.11) unstable; urgency=low 1086 | 1087 | * Improve handling the 'No space left on device' situation through 1088 | using an according rsync handler function. 1089 | 1090 | -- Michael Prokop Mon, 07 Sep 2009 23:05:30 +0200 1091 | 1092 | grml2usb (0.9.10) unstable; urgency=low 1093 | 1094 | * Support the directory where the grml2usb script resides as base 1095 | directory so /usr/share/grml2usb isn't necessarily needed. 1096 | Thanks for the patch to Alexander 'Leo' Bergolth ! 1097 | * Make sure grub.conf isn't a symlink but a plain file instead, 1098 | otherwise it will break on FAT16 filesystems. This works around 1099 | grub-install of (at least) Fedora 10. 1100 | Thanks for the patch to Alexander 'Leo' Bergolth ! 1101 | * Use 'pci=nomsi' in failsafe bootoption. Thanks to Marc 'HE' Brockschmidt. 1102 | * Mention the --syslinux option if grub-install fails. 1103 | * Fix usage of --force in combination with --fat16. Thanks to 1104 | Johannes Endres and Reiko Kaps for the bugreport. 1105 | * Replace hint to '--grub' with 'grub'. 1106 | * New option --grub-mbr which allows installation of grub in MBR instead 1107 | of installation into a partition (PBR) which is necessary when using grub2. 1108 | 1109 | -- Michael Prokop Mon, 07 Sep 2009 17:12:54 +0200 1110 | 1111 | grml2usb (0.9.9) unstable; urgency=low 1112 | 1113 | * Use ascii.pf2 as grub2 font, since grub2 (1.96+20090307-1) 1114 | the old ascii.pff isn't available anymore. 1115 | * Use terminal_output if available, otherwise fallback to old 1116 | older 'terminal'-command (thanks to Felix Zielcke for helping). 1117 | * Document the 'grub-setup fails after Attempting to install GRUB 1118 | to a partition instead of the MBR' issue. 1119 | * Use "set gfxpayload=1024x768x16,1024x768" instead of vga=791 in 1120 | grub2 configuration. This requires a recent version of the linux 1121 | loader as the new linux loader loads the kernel at 32bit entry point 1122 | and not at 16 bit anymore so it has to be translated for the Linux 1123 | kernel (as the kernel parses vga= in 16 bit code). In the long run 1124 | we don't seem to have another option, so let's change it. 1125 | Thanks to Felix Zielcke and Robert Millan for first hand information. 1126 | * Increase timeout from 5 to 10 seconds in grub2 configuration. 1127 | * Load memtest86+ binary via 'linux16' in grub2 (otherwise it fails). 1128 | * Drop the serial boot entry from grub2 (I assume users with usb 1129 | pens don't need that option). 1130 | * Change the way MirOS bsd4grml is loaded (use the fallback method 1131 | as default). 1132 | * Improve descriptions of grml's grub2 entries. 1133 | * Bump Standards-Version to 3.8.3 (no further changes). 1134 | * Fix creation and installation of grub1's configuration file (menu.lst). 1135 | Thanks to Mario 'BitKoenig' Holbe. 1136 | 1137 | -- Michael Prokop Tue, 25 Aug 2009 23:53:51 +0200 1138 | 1139 | grml2usb (0.9.8) unstable; urgency=low 1140 | 1141 | * Support installation on /dev/loop*-devices. 1142 | * Generate configuration for syslinux and grub by default, no 1143 | matter which bootloader the users chooses. 1144 | * Added options --skip-syslinux-config and --skip-grub-config 1145 | if someone wants to skip the generation of any bootloader 1146 | configuration files. 1147 | * Make sure grub-install is available before executing it. 1148 | * Display information about default grml flavour and the other 1149 | available grml flavours at the end of the grml2usb run. 1150 | * Use /sbin/blkid (e2fsprogs) instead of vol_id as vol_id is going to be 1151 | removed from udev. Thanks for the patch to Andras Korn! 1152 | * Use rsync instead of cp. Thanks for the patch to Andras Korn! 1153 | [Closes: issue683] 1154 | * Use 'forensic' and 'readonly' in the forensic bootoption itself. 1155 | * Spelling fixes (thanks to Thorsten Glaser ). 1156 | * Write GRUB2 config even if the target is a directory (thanks, Thorsten) 1157 | * All these "set root=" are not needed for GRUB2 (thanks, Thorsten) 1158 | * Switch order of check whether the specified device is a directory 1159 | and check for usb device (as the usb device check will fail if 1160 | it's a directory). 1161 | * Add grml2iso for creating a bootable DVD: 1162 | - thanks once more to Thorsten Glaser for helping and patches 1163 | - thanks to Ernesto Domato for reporting the issue regarding 1164 | i386<->amd64 with grub-mkimage 1165 | * Move syslinux check to install_syslinux_mbr() 1166 | * Drop the reference to --grub option (thanks for the bugreport 1167 | to Peter Palfrader) 1168 | * Update documentation: 1169 | - mention the dd approach 1170 | - mention grml2iso 1171 | - improve section link names for the online version 1172 | - add 'grub-probe: error: unknown filesystem' 1173 | * Support use with python version 2.4. 1174 | * Bump Standard Version to 3.8.2 (no further changes). 1175 | * Depend on debhelper >=5 (using compat version 5). 1176 | 1177 | -- Michael Prokop Tue, 21 Jul 2009 18:01:50 +0200 1178 | 1179 | grml2usb (0.9.7) unstable; urgency=low 1180 | 1181 | * Fix typo in manpage of grml2usb (thanks to Wernfried Haas). 1182 | * Fix bootoption toram: it should be toram=$FLAVOUR.squashfs instead 1183 | of toram=$FLAVOUR. Thanks to Wernfried Haas and Frank Prochnow 1184 | for the bugreport and debugging! [Closes: issue680] 1185 | 1186 | -- Michael Prokop Tue, 02 Jun 2009 23:32:13 +0200 1187 | 1188 | grml2usb (0.9.6) unstable; urgency=low 1189 | 1190 | * Support installation of the currently running grml live 1191 | system ("grml2usb /live/image /dev/sdx1"). 1192 | * Add "persistent" entry to grub/syslinux menu. [Closes: issue669] 1193 | 1194 | -- Michael Prokop Wed, 20 May 2009 19:32:02 +0200 1195 | 1196 | grml2usb (0.9.5) unstable; urgency=low 1197 | 1198 | * Fix dashes of options in manpage (thanks for the bugreport, 1199 | Thorsten Glaser). 1200 | * Display program version during execution. 1201 | * Apply fix by Peter Daum , making sure 1202 | to use the normalized path for unmounting. Thanks! 1203 | * Use 'multiboot' for booting MirOS BSD when using grub2. 1204 | * Catch exception if copying files fails. 1205 | * Make sure to exit if installing grub fails. 1206 | * Integrate hdt (Hardware Detection Tool) in bootsplash (but 1207 | only if using syslinux as grub isn't supported). 1208 | 1209 | -- Michael Prokop Mon, 04 May 2009 22:31:30 +0200 1210 | 1211 | grml2usb (0.9.4) unstable; urgency=low 1212 | 1213 | * Bugfix: move kernel commandline from initrd to kernel option in 1214 | generate_flavour_specific_grub2_config(). 1215 | 1216 | -- Michael Prokop Thu, 09 Apr 2009 00:04:56 +0200 1217 | 1218 | grml2usb (0.9.3) unstable; urgency=low 1219 | 1220 | * Drop some leftover 'lang=us' references. 1221 | * Update mbr.S (thanks, Thorsten Glaser). 1222 | * Rename --mbr-manager into --mbr-menu (people seem to be confused 1223 | what this option does). Improve the according documentation. 1224 | * Update failsafe bootoption. 1225 | * Fix comments section in manpage (thanks for reporting, 1226 | Alexander Steinböck). 1227 | * Mention the Debian package in the error message (thanks to 1228 | Lothar Speil for the bugreport). 1229 | * Mention grml-repository in the docs. 1230 | * Support older kernel versions in check for removable usb device. 1231 | (Thanks to Ralf Gross for the report and relevant information.) 1232 | * Also add specified bootoptions to default entry in configuration 1233 | file of grub version 1. (Thanks to Ralf Gross for the bugreport.) 1234 | * Make sure that options "--quiet" and "--verbose" aren't accepted 1235 | at the same time in the command line. Thanks for bugreport and 1236 | code example, Karl Voit! 1237 | * Bump Standard Version to 3.8.1 (no further changes). 1238 | * Set debhelper's compat version from 4 to 5. 1239 | 1240 | -- Michael Prokop Wed, 08 Apr 2009 00:09:46 +0200 1241 | 1242 | grml2usb (0.9.2) unstable; urgency=low 1243 | 1244 | * Rewrote grml2usb from scratch (in python). New features: 1245 | - you no longer need to setup the device via /etc/fstab, just 1246 | directly invoke "grml2usb /path/to/iso /dev/sdb1" 1247 | - initial multi-iso / multi-boot support 1248 | [Closes: issue501] [Closes: issue584] 1249 | - provide *several* new options like --bootloader-only, 1250 | --bootoptions=... check out the manpage for all the details 1251 | - get rid of "polution" of root directory on usb-pen 1252 | [Closes: issue466] 1253 | - always write a default MBR (thanks a lot to the work 1254 | and help of Thorsten Glaser!) [Closes: issue295] 1255 | - use grub by default (but support for syslinux is present as 1256 | well of course) 1257 | - fix regressions for temporary mountpoints / wrong directories 1258 | [Closes: issue603] [Closes: issue602] 1259 | * Update debian stuff: 1260 | - Bump Standard Version to 3.8.0 (no further changes) 1261 | - Change XS-Vcs-* to Vcs-* headers and replace mercurial with 1262 | grml's nowadays git repository URLs 1263 | - drop mtools from depends 1264 | - slightly improve long description 1265 | - add asciidoc, xsltproc and docbook-xsl to Build-Depends 1266 | - either depend on syslinux | grub2 | grub 1267 | 1268 | -- Michael Prokop Mon, 02 Mar 2009 16:40:55 +0100 1269 | 1270 | grml2usb (0.9.1) unstable; urgency=low 1271 | 1272 | * Fix problem with comment chars in /etc/fstab. 1273 | Thanks for debugging and the patch to Robert Euhus! 1274 | * Some minor cleanups in Debian packaging. 1275 | 1276 | -- Michael Prokop Sun, 25 May 2008 01:29:30 +0200 1277 | 1278 | grml2usb (0.9.0) unstable; urgency=low 1279 | 1280 | * Support new directory layout of different grml-flavours 1281 | * Fix uninstall option (really clean up usb device) 1282 | 1283 | -- Michael Prokop Sat, 23 Feb 2008 23:43:57 +0100 1284 | 1285 | grml2usb (0.8.0) unstable; urgency=low 1286 | 1287 | * Fix the "mv: cannot move `/mnt/usb-sdb1/boot/grub' to a subdirectory of 1288 | itself, `/mnt/usb-sdb1/grub'" issue. 1289 | 1290 | -- Michael Prokop Sat, 19 Jan 2008 16:57:08 +0100 1291 | 1292 | grml2usb (0.7.8) unstable; urgency=low 1293 | 1294 | * Adjust grml2usb for a present grub directory. 1295 | 1296 | -- Michael Prokop Fri, 16 Nov 2007 08:29:20 +0100 1297 | 1298 | grml2usb (0.7.7) unstable; urgency=low 1299 | 1300 | * Improve error handling for execution of syslinux. 1301 | 1302 | -- Michael Prokop Thu, 13 Sep 2007 01:38:31 +0200 1303 | 1304 | grml2usb (0.7.6) unstable; urgency=low 1305 | 1306 | * The "reworked grml2usb for JUXLALA"-release. 1307 | * Added fs check via vol_id. 1308 | * Improved error handling. 1309 | * Fixed some code parts regarding use of $TMPMNT. 1310 | 1311 | -- Michael Prokop Fri, 08 Jun 2007 18:07:09 +0200 1312 | 1313 | grml2usb (0.7.5) unstable; urgency=low 1314 | 1315 | * supporting directories and direct blockdevices as source for the iso. 1316 | 1317 | -- Michael Gebetsroither Tue, 03 Apr 2007 23:28:19 +0200 1318 | 1319 | grml2usb (0.7.4) unstable; urgency=low 1320 | 1321 | * Get rid of bashism, thanks for reporting - Paul Weaver! 1322 | * Change version schema from x.y-z to x.y.z. 1323 | 1324 | -- Michael Prokop Fri, 16 Mar 2007 14:43:49 +0100 1325 | 1326 | grml2usb (0.7-3) unstable; urgency=low 1327 | 1328 | * The manpage was just a template, added the missing documentation 1329 | now. Thanks for reporting, Jens Heidrich! 1330 | 1331 | -- Michael Prokop Sat, 3 Feb 2007 11:08:30 +0100 1332 | 1333 | grml2usb (0.7-2) unstable; urgency=low 1334 | 1335 | * Use 'Architecture: all' in debian/control so we can use the 1336 | package on non-x86 as well. 1337 | * Bumb Standard Version to 3.7.2 (no further changes). 1338 | 1339 | -- Michael Prokop Sat, 11 Nov 2006 12:46:35 +0100 1340 | 1341 | grml2usb (0.7-1) unstable; urgency=low 1342 | 1343 | * Use different exit codes for different code parts, and quote 1344 | $ISO, thanks - Richard Hartmann! 1345 | * Remove unused configure lines in debian/rules. 1346 | 1347 | -- Michael Prokop Mon, 6 Nov 2006 23:48:46 +0100 1348 | 1349 | grml2usb (0.6-1) unstable; urgency=low 1350 | 1351 | * Allow overwriting of $TMPMNT. 1352 | 1353 | -- Michael Prokop Wed, 4 Oct 2006 22:50:58 +0200 1354 | 1355 | grml2usb (0.5-1) unstable; urgency=low 1356 | 1357 | * bailout if mounting of target device failes. 1358 | 1359 | -- Michael Prokop Mon, 11 Sep 2006 23:47:01 +0200 1360 | 1361 | grml2usb (0.4-1) unstable; urgency=low 1362 | 1363 | * Check for existence of syslinux before running the script. 1364 | * Updated copyright file (new fsfs address). 1365 | 1366 | -- Michael Prokop Sat, 3 Jun 2006 21:02:53 +0200 1367 | 1368 | grml2usb (0.3-1) unstable; urgency=low 1369 | 1370 | * Added uninstall option. 1371 | * Improved error handling and its output. 1372 | * Added colors to improve manual text parsing. 1373 | 1374 | -- Michael Prokop Fri, 10 Mar 2006 20:19:28 +0100 1375 | 1376 | grml2usb (0.2-1) unstable; urgency=low 1377 | 1378 | * Improved usage information. 1379 | 1380 | -- Michael Prokop Tue, 10 Jan 2006 09:35:20 +0100 1381 | 1382 | grml2usb (0.1-3) unstable; urgency=low 1383 | 1384 | * Changed 'cp -a' to 'cp -dR --preserve=mode,timestamps' so we don't 1385 | get the ownership-permission-warnings. 1386 | 1387 | -- Michael Prokop Fri, 2 Sep 2005 18:02:22 +0200 1388 | 1389 | grml2usb (0.1-2) unstable; urgency=low 1390 | 1391 | * Fixed small typo (SYSDEV/TMPDEV) [thanks for hint, tklauser!]. 1392 | 1393 | -- Michael Prokop Wed, 17 Aug 2005 21:50:32 +0200 1394 | 1395 | grml2usb (0.1-1) unstable; urgency=low 1396 | 1397 | * Initial release. 1398 | 1399 | -- Michael Prokop Sun, 14 Aug 2005 15:31:04 +0200 1400 | 1401 | -------------------------------------------------------------------------------- /grml2usb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # pylint: disable-msg=C0302 4 | """ 5 | grml2usb 6 | ~~~~~~~~ 7 | 8 | This script installs a Grml system (either a running system or ISO[s]) to a USB device 9 | 10 | :copyright: (c) 2009-2025 by Michael Prokop 11 | :license: GPL v2 or any later version 12 | :bugreports: http://grml.org/bugs/ 13 | 14 | """ 15 | 16 | import argparse 17 | import fileinput 18 | import functools 19 | import glob 20 | import logging 21 | import os 22 | import os.path 23 | import re 24 | import shutil 25 | import subprocess 26 | import sys 27 | import tempfile 28 | import uuid 29 | from inspect import isclass, isroutine 30 | 31 | # The line following this line is patched by debian/rules and tarball.sh. 32 | PROG_VERSION = "***UNKNOWN***" 33 | 34 | # when running from inside git, try to report version information via git-describe 35 | try: 36 | git_dir = os.path.abspath(os.path.dirname(sys.argv[0])) 37 | with open(os.devnull, "w") as devnull: 38 | PROG_VERSION = ( 39 | subprocess.check_output( 40 | ["git", "-C", git_dir, "describe", "--always", "--dirty"], 41 | stderr=devnull, 42 | ) 43 | .strip() 44 | .decode("utf-8", errors="replace") 45 | + " (git)" 46 | ) 47 | except Exception: 48 | pass 49 | 50 | # global variables 51 | MOUNTED = set() # register mountpoints 52 | TMPFILES = set() # register tmpfiles 53 | GRML_FLAVOURS = set() # which flavours are being installed? 54 | GRML_DEFAULT = None 55 | SYSLINUX_LIBS = [ 56 | "/usr/lib/syslinux/modules/bios/", # Debian 57 | "/usr/lib/syslinux/bios/", # Arch Linux 58 | ] 59 | GRUB_INSTALL = None 60 | 61 | RE_PARTITION = re.compile(r"([a-z/]*?)(\d+)$") 62 | RE_P_PARTITION = re.compile(r"(.*?\d+)p(\d+)$") 63 | RE_LOOP_DEVICE = re.compile(r"/dev/loop\d+$") 64 | 65 | 66 | # cmdline parsing 67 | USAGE = "Usage: %(prog)s [options] <[ISO[s] | /run/live/medium]> \n\ 68 | \n\ 69 | %(prog)s installs Grml ISO[s] to an USB device to be able to boot from it.\n\ 70 | Make sure you have at least one Grml ISO or a running Grml system (/run/live/medium),\n\ 71 | grub or syslinux and root access.\n\ 72 | \n\ 73 | Run %(prog)s --help for usage hints, further information via: man grml2usb" 74 | 75 | # pylint: disable-msg=C0103 76 | # pylint: disable-msg=W0603 77 | parser = argparse.ArgumentParser(usage=USAGE) 78 | bootloader_group = parser.add_mutually_exclusive_group() 79 | fat_group = parser.add_mutually_exclusive_group() 80 | 81 | parser.add_argument( 82 | "--bootoptions", 83 | action="append", 84 | type=str, 85 | help="use specified bootoptions as default", 86 | ) 87 | parser.add_argument( 88 | "--bootloader-only", 89 | dest="bootloaderonly", 90 | action="store_true", 91 | help="do not copy files but just install a bootloader", 92 | ) 93 | parser.add_argument( 94 | "--copy-only", 95 | dest="copyonly", 96 | action="store_true", 97 | help="copy files only but do not install bootloader", 98 | ) 99 | parser.add_argument( 100 | "--dry-run", dest="dryrun", action="store_true", help="avoid executing commands" 101 | ) 102 | fat_group.add_argument( 103 | "--format", 104 | action="store_true", 105 | help="format specified partition with fat", 106 | ) 107 | fat_group.add_argument( 108 | "--fat16", 109 | action="store_true", 110 | # deprecated=True, # python>=3.13 111 | dest="format", 112 | help="format specified partition with fat (deprecated option)", 113 | ) 114 | parser.add_argument( 115 | "--force", 116 | action="store_true", 117 | help="force any actions requiring manual interaction", 118 | ) 119 | parser.add_argument( 120 | "--grub-mbr", 121 | dest="grubmbr", 122 | action="store_true", 123 | help="install grub into MBR instead of (default) PBR", 124 | ) 125 | parser.add_argument( 126 | "--mbr-menu", 127 | dest="mbrmenu", 128 | action="store_true", 129 | help="enable interactive boot menu in MBR", 130 | ) 131 | parser.add_argument( 132 | "--quiet", 133 | action="store_true", 134 | help="do not output anything but just errors on console", 135 | ) 136 | parser.add_argument( 137 | "--remove-bootoption", 138 | dest="removeoption", 139 | action="append", 140 | help="regex for removing existing bootoptions", 141 | ) 142 | parser.add_argument( 143 | "--rw-blockdev", 144 | dest="rwblockdev", 145 | action="store_true", 146 | help="enforce read-write mode on involved block devices", 147 | ) 148 | parser.add_argument( 149 | "--skip-addons", 150 | dest="skipaddons", 151 | action="store_true", 152 | help="do not install /boot/addons/ files", 153 | ) 154 | parser.add_argument( 155 | "--skip-bootflag", 156 | dest="skipbootflag", 157 | action="store_true", 158 | help="do not try to check whether the destination has the boot flag set", 159 | ) 160 | parser.add_argument( 161 | "--skip-grub-config", 162 | dest="skipgrubconfig", 163 | action="store_true", 164 | help="skip generation of grub configuration files", 165 | ) 166 | parser.add_argument( 167 | "--skip-mbr", 168 | dest="skipmbr", 169 | action="store_true", 170 | help="do not install a master boot record (MBR) on the device", 171 | ) 172 | parser.add_argument( 173 | "--skip-syslinux-config", 174 | dest="skipsyslinuxconfig", 175 | action="store_true", 176 | help="skip generation of syslinux configuration files", 177 | ) 178 | parser.add_argument( 179 | "--skip-usb-check", 180 | dest="skipusbcheck", 181 | action="store_true", 182 | help="skip check to verify whether given device is removable", 183 | ) 184 | parser.add_argument( 185 | "--syslinux-mbr", 186 | dest="syslinuxmbr", 187 | action="store_true", 188 | help="install syslinux master boot record (MBR) instead of default", 189 | ) 190 | parser.add_argument( 191 | "--syslinux-libs", 192 | dest="syslinuxlibs", 193 | action="append", 194 | default=[], 195 | help="syslinux modules directory path", 196 | ) 197 | parser.add_argument( 198 | "--tmpdir", 199 | default="/tmp", 200 | help="directory to be used for temporary files", 201 | ) 202 | parser.add_argument( 203 | "--verbose", 204 | action="store_true", 205 | help="enable verbose mode", 206 | ) 207 | parser.add_argument( 208 | "--version", 209 | "-v", 210 | action="version", 211 | version=f"%(prog)s {PROG_VERSION}", 212 | help="display version and exit", 213 | ) 214 | 215 | bootloader_group.add_argument( 216 | "--bootloader", 217 | default="auto", 218 | choices=["auto", "syslinux", "grub", "efi"], 219 | help="Select bootloader to install", 220 | ) 221 | bootloader_group.add_argument( 222 | "--grub", 223 | dest="bootloader", 224 | action="store_const", 225 | # deprecated=True, # python>=3.13 226 | const="grub", 227 | help="install grub bootloader (deprecated option)", 228 | ) 229 | bootloader_group.add_argument( 230 | "--syslinux", 231 | dest="bootloader", 232 | action="store_const", 233 | # deprecated=True, # python>=3.13 234 | const="syslinux", 235 | help="install syslinux bootloader (deprecated option)", 236 | ) 237 | 238 | parser.add_argument( 239 | "isos", 240 | nargs="+", 241 | help="ISOs to install", 242 | ) 243 | parser.add_argument( 244 | "device", 245 | help="Partition on USB Device to install on", 246 | ) 247 | 248 | # will be overwritten at the bottom of this file. 249 | options: argparse.Namespace | None = None 250 | 251 | 252 | GRML2USB_BASE = "/usr/share/grml2usb" 253 | if not os.path.isdir(GRML2USB_BASE): 254 | GRML2USB_BASE = os.path.dirname(os.path.realpath(__file__)) 255 | 256 | 257 | class HodorException(Exception): 258 | """Throw exception if the exact error is not known and not fatal. 259 | 260 | @Exception: message""" 261 | 262 | 263 | class CriticalException(Exception): 264 | """Throw critical exception if the exact error is not known but fatal. 265 | 266 | @Exception: message""" 267 | 268 | 269 | class VerifyException(Exception): 270 | """Throw critical exception if there is an fatal error when verifying something. 271 | 272 | @Exception: message""" 273 | 274 | 275 | def cleanup(): 276 | """Cleanup function to make sure there aren't any mounted devices left behind.""" 277 | 278 | def del_failed(_fn, path, _exc): 279 | logging.warning("Deletion of %s failed in temporary folder", path) 280 | 281 | logging.info("Cleaning up before exiting...") 282 | proc = subprocess.Popen(["sync"]) 283 | proc.wait() 284 | 285 | for device in MOUNTED.copy(): 286 | try: 287 | unmount(device, "") 288 | logging.debug("Unmounted %s" % device) 289 | except Exception: 290 | logging.debug("RuntimeError while umount %s, ignoring" % device) 291 | 292 | for tmppath in TMPFILES.copy(): 293 | try: 294 | if os.path.isdir(tmppath) and not os.path.islink(tmppath): 295 | # symbolic links to directories are ignored 296 | # without the check it will throw an OSError 297 | shutil.rmtree(tmppath, onerror=del_failed) 298 | logging.debug("temporary directory %s deleted" % tmppath) 299 | unregister_tmpfile(tmppath) 300 | elif os.path.isfile(tmppath): 301 | os.unlink(tmppath) 302 | logging.debug("temporary file %s deleted" % tmppath) 303 | unregister_tmpfile(tmppath) 304 | except Exception: 305 | msg = "RuntimeError while removing temporary %s, ignoring" 306 | logging.debug(msg % tmppath) 307 | 308 | 309 | def register_tmpfile(path): 310 | """ 311 | register tmpfile 312 | """ 313 | 314 | TMPFILES.add(path) 315 | 316 | 317 | def unregister_tmpfile(path): 318 | """ 319 | remove registered tmpfile 320 | """ 321 | 322 | try: 323 | TMPFILES.remove(path) 324 | except KeyError: 325 | pass 326 | 327 | 328 | def register_mountpoint(target): 329 | """register specified target in a set() for handling clean exiting 330 | 331 | @target: destination target of mountpoint 332 | """ 333 | 334 | MOUNTED.add(target) 335 | 336 | 337 | def unregister_mountpoint(target): 338 | """unregister specified target in a set() for handling clean exiting 339 | 340 | @target: destination target of mountpoint 341 | """ 342 | 343 | if target in MOUNTED: 344 | MOUNTED.remove(target) 345 | 346 | 347 | def get_function_name(obj): 348 | """Helper function for use in execute() to retrieve name of a function 349 | 350 | @obj: the function object 351 | """ 352 | if not (isroutine(obj) or isclass(obj)): 353 | obj = type(obj) 354 | return obj.__module__ + "." + obj.__name__ 355 | 356 | 357 | def run_program(args, check: bool = True, **kwargs): 358 | # str-ify Paths, not necessary, but for readability in logs. 359 | args = [arg if isinstance(arg, str) else str(arg) for arg in args] 360 | args_str = '" "'.join(args) 361 | logging.debug('Running "%s"', args_str) 362 | return subprocess.run(args, check=check, **kwargs) 363 | 364 | 365 | def set_rw(device): 366 | assert options is not None 367 | if not options.rwblockdev: 368 | return 369 | 370 | logging.debug("executing: blockdev --setrw %s", device) 371 | proc = subprocess.Popen(["blockdev", "--setrw", device]) 372 | proc.wait() 373 | if proc.returncode != 0: 374 | raise Exception("error executing blockdev on %s" % device) 375 | 376 | 377 | def execute(f, *exec_arguments): 378 | """Wrapper for executing a command. Either really executes 379 | the command (default) or when using --dry-run commandline option 380 | just displays what would be executed.""" 381 | assert options is not None 382 | # usage: execute(subprocess.Popen, (["ls", "-la"])) 383 | if options.dryrun: 384 | # pylint: disable-msg=W0141 385 | logging.debug( 386 | "dry-run only: %s(%s)", 387 | get_function_name(f), 388 | ", ".join(map(repr, exec_arguments)), 389 | ) 390 | else: 391 | # pylint: disable-msg=W0142 392 | return f(*exec_arguments) 393 | 394 | 395 | def is_exe(fpath): 396 | """Check whether a given file can be executed 397 | 398 | @fpath: full path to file 399 | @return:""" 400 | return os.path.exists(fpath) and os.access(fpath, os.X_OK) 401 | 402 | 403 | def which(program): 404 | """Check whether a given program is available in PATH 405 | 406 | @program: name of executable""" 407 | fpath = os.path.split(program)[0] 408 | if fpath: 409 | if is_exe(program): 410 | return program 411 | else: 412 | for path in os.environ["PATH"].split(os.pathsep): 413 | exe_file = os.path.join(path, program) 414 | if is_exe(exe_file): 415 | return exe_file 416 | 417 | return None 418 | 419 | 420 | def get_defaults_file(iso_mount, flavour, name): 421 | """get the default file for syslinux""" 422 | bootloader_dirs = ["/boot/isolinux/", "/boot/syslinux/"] 423 | for directory in bootloader_dirs: 424 | for name in name, "%s_%s" % (get_flavour_filename(flavour), name): 425 | if os.path.isfile(iso_mount + directory + name): 426 | return (directory, name) 427 | return ("", "") 428 | 429 | 430 | def search_file( 431 | filename, 432 | search_path="/bin" + os.pathsep + "/usr/bin", 433 | lst_return=False, 434 | required=False, 435 | ): 436 | """Given a search path, find file 437 | 438 | @filename: name of file to search for 439 | @search_path: path where searching for the specified filename 440 | @lst_return: return list of matching files instead one file""" 441 | paths = search_path.split(os.pathsep) 442 | current_dir = "" # make pylint happy :) 443 | retval = [] 444 | 445 | def match_file(cwd): 446 | """Helper function ffor testing if specified file exists in cwd 447 | 448 | @cwd: current working directory 449 | """ 450 | return os.path.exists(os.path.join(cwd, filename)) 451 | 452 | for path in paths: 453 | current_dir = path 454 | if match_file(current_dir): 455 | retval.append(os.path.abspath(os.path.join(current_dir, filename))) 456 | if not lst_return: 457 | break 458 | for current_dir, _directories, _files in os.walk(path): 459 | if match_file(current_dir): 460 | retval.append(os.path.abspath(os.path.join(current_dir, filename))) 461 | if not lst_return: 462 | break 463 | 464 | if required and not retval: 465 | raise CriticalException( 466 | "Required file %s not found in %s" % (filename, search_path) 467 | ) 468 | 469 | if lst_return: 470 | return retval 471 | elif retval: 472 | return retval[0] 473 | else: 474 | return None 475 | 476 | 477 | def check_uid_root(): 478 | """Check for root permissions""" 479 | if not os.geteuid() == 0: 480 | raise CriticalException("please run this script with uid 0 (root).") 481 | 482 | 483 | # for usage inside check_boot_flag 484 | def get_partition_for_path(path): 485 | import parted 486 | 487 | boot_dev, x = get_device_from_partition(path) 488 | 489 | d = parted.getDevice(boot_dev) 490 | disk = parted.Disk(d) 491 | return disk.getPartitionByPath(path) 492 | 493 | 494 | def check_boot_flag(device): 495 | if os.path.isdir(device): 496 | logging.debug( 497 | "Device %s is a directory, skipping check for boot flag." % device 498 | ) 499 | return 500 | 501 | boot_dev, x = get_device_from_partition(device) 502 | 503 | logging.info("Checking for boot flag") 504 | try: 505 | import parted 506 | 507 | part = get_partition_for_path(device) 508 | if part is None: 509 | raise HodorException("parted could not find partition") 510 | if part.getFlag(parted.PARTITION_BOOT): 511 | logging.debug("boot flag is enabled on %s" % device) 512 | return 513 | else: 514 | logging.debug("boot flag is NOT enabled on %s" % device) 515 | raise VerifyException( 516 | "Device %s does not have the boot flag set. " 517 | "Please enable it to be able to boot." % device 518 | ) 519 | except ImportError: 520 | raise VerifyException( 521 | "Could not import parted to verify boot flag on %s, please make sure python3-parted is installed." 522 | % device 523 | ) 524 | 525 | 526 | def mkfs_vfat(device): 527 | """Format specified device with FAT filesystem. 528 | 529 | @device: partition that should be formated""" 530 | assert options is not None 531 | 532 | if options.dryrun: 533 | logging.info("Would execute mkfs.vfat %s now.", device) 534 | return 0 535 | 536 | logging.info("Formatting partition using mkfs.vfat") 537 | logging.debug("mkfs.vfat %s", device) 538 | proc = subprocess.Popen(["mkfs.vfat", "-n", "GRML", device]) 539 | proc.wait() 540 | if proc.returncode != 0: 541 | raise CriticalException("error executing mkfs.vfat") 542 | 543 | 544 | def generate_main_syslinux_config(): 545 | """Generate main configuration for use in syslinux.cfg""" 546 | 547 | return """\ 548 | label - 549 | menu label Default boot modes: 550 | menu disable 551 | include defaults.cfg 552 | 553 | menu end 554 | menu separator 555 | 556 | # flavours: 557 | label - 558 | menu label Additional boot entries for: 559 | menu disable 560 | include additional.cfg 561 | 562 | menu separator 563 | include options.cfg 564 | include addons.cfg 565 | 566 | label help 567 | include promptname.cfg 568 | config prompt.cfg 569 | text help 570 | Jump to old style isolinux prompt 571 | featuring further information 572 | regarding available boot options. 573 | endtext 574 | 575 | 576 | include hiddens.cfg 577 | """ 578 | 579 | 580 | def generate_flavour_specific_syslinux_config(grml_flavour): 581 | """Generate flavour specific configuration for use in syslinux.cfg 582 | 583 | @grml_flavour: name of grml flavour the configuration should be generated for""" 584 | 585 | return """\ 586 | menu begin grml %(grml_flavour)s 587 | menu title %(display_name)s 588 | label mainmenu 589 | menu label ^Back to main menu... 590 | menu exit 591 | menu separator 592 | # include config for boot parameters from disk 593 | include %(grml_flavour)s_grml.cfg 594 | menu hide 595 | menu end 596 | """ % { 597 | "grml_flavour": grml_flavour, 598 | "display_name": get_flavour_filename(grml_flavour), 599 | } 600 | 601 | 602 | def install_grub(device): 603 | """Install grub on specified device. 604 | 605 | @mntpoint: mountpoint of device where grub should install its files to 606 | @device: partition where grub should be installed to""" 607 | assert options is not None 608 | 609 | if options.dryrun: 610 | logging.info( 611 | "Would execute grub-install [--root-directory=mount_point] %s now.", device 612 | ) 613 | else: 614 | device_mountpoint = tempfile.mkdtemp(prefix="grml2usb") 615 | register_tmpfile(device_mountpoint) 616 | try: 617 | # If using --grub-mbr then make sure we install grub in MBR instead of PBR 618 | if options.grubmbr: 619 | logging.debug("Using option --grub-mbr ...") 620 | grub_device, x = get_device_from_partition(device) 621 | else: 622 | grub_device = device 623 | 624 | set_rw(device) 625 | mount(device, device_mountpoint, "") 626 | 627 | logging.info("Installing grub as bootloader") 628 | for opt in ["--", "--force"]: 629 | set_rw(device) 630 | set_rw(grub_device) 631 | logging.debug( 632 | "%s --recheck --no-floppy --target=i386-pc --root-directory=%s %s %s", 633 | GRUB_INSTALL, 634 | device_mountpoint, 635 | opt, 636 | grub_device, 637 | ) 638 | proc = subprocess.Popen( 639 | [ 640 | GRUB_INSTALL, 641 | "--recheck", 642 | "--no-floppy", 643 | "--target=i386-pc", 644 | "--root-directory=%s" % device_mountpoint, 645 | opt, 646 | grub_device, 647 | ], 648 | stdout=open(os.devnull, "r+"), 649 | ) 650 | proc.wait() 651 | if proc.returncode == 0: 652 | break 653 | 654 | if proc.returncode != 0: 655 | # raise Exception("error executing grub-install") 656 | logging.critical( 657 | "Fatal: error executing grub-install " 658 | "(please check the grml2usb FAQ or drop the --grub option)" 659 | ) 660 | logging.critical( 661 | "Note: if using grub2 consider using " 662 | "the --grub-mbr option as grub considers PBR problematic." 663 | ) 664 | cleanup() 665 | sys.exit(1) 666 | except CriticalException as error: 667 | logging.critical("Fatal: %s", error) 668 | cleanup() 669 | sys.exit(1) 670 | finally: 671 | unmount(device_mountpoint, "") 672 | os.rmdir(device_mountpoint) 673 | unregister_tmpfile(device_mountpoint) 674 | 675 | 676 | def install_syslinux(device): 677 | """Install syslinux on specified device. 678 | 679 | @device: partition where syslinux should be installed to""" 680 | 681 | if options.dryrun: 682 | logging.info("Would install syslinux as bootloader on %s", device) 683 | return 0 684 | 685 | set_rw(device) 686 | 687 | # syslinux -d boot/isolinux /dev/sdb1 688 | logging.info("Installing syslinux as bootloader") 689 | logging.debug("syslinux -d boot/syslinux %s", device) 690 | proc = subprocess.Popen(["syslinux", "-d", "boot/syslinux", device]) 691 | proc.wait() 692 | if proc.returncode != 0: 693 | raise CriticalException( 694 | "Error executing syslinux (either try --format or use grub?)" 695 | ) 696 | 697 | 698 | def install_bootloader(device): 699 | """Install bootloader on specified device. 700 | 701 | @device: partition where bootloader should be installed to""" 702 | assert options is not None 703 | 704 | # by default we use grub, so install syslinux only on request 705 | if options.bootloader == "grub": 706 | try: 707 | install_grub(device) 708 | except CriticalException as error: 709 | logging.critical("Fatal: %s", error) 710 | cleanup() 711 | sys.exit(1) 712 | elif options.bootloader == "syslinux": 713 | try: 714 | install_syslinux(device) 715 | except CriticalException as error: 716 | logging.critical("Fatal: %s", error) 717 | cleanup() 718 | sys.exit(1) 719 | 720 | 721 | def install_mbr(mbrtemplate, device, partition, ismirbsdmbr=True): 722 | """install 'mbr' master boot record (MBR) on a device 723 | 724 | Retrieve the partition table from "device", install an MBR from the 725 | "mbrtemplate" file, set the "partition" (0..3) active, and install the 726 | result back to "device". 727 | 728 | @mbrtemplate: default MBR file (must be a valid MBR file of at least 440 729 | (or 439 if ismirbsdmbr) bytes) 730 | 731 | @device: name of a file assumed to be a hard disc (or USB stick) image, or 732 | something like "/dev/sdb" 733 | 734 | @partition: must be a number between 0 and 3, inclusive 735 | 736 | @ismirbsdmbr: if true then ignore the active flag, set the mirbsdmbr 737 | specific flag to 0/1/2/3 and set the MBR's default value accordingly. If 738 | false then leave the mirbsdmbr specific flag set to FFh, set all 739 | active flags to 0 and set the active flag of the partition to 80h. Note: 740 | behaviour of mirbsdmbr: if flag = 0/1/2/3 then use it, otherwise search for 741 | the active flag.""" 742 | assert options is not None 743 | if options.bootloader == "efi": 744 | logging.info("Skipping MBR installation for EFI-boot") 745 | return 746 | 747 | logging.info("Installing default MBR") 748 | 749 | if not os.path.isfile(mbrtemplate): 750 | logging.error( 751 | "Error installing MBR (either try --syslinux-mbr or " 752 | 'install missing file "%s"?)', 753 | mbrtemplate, 754 | ) 755 | raise CriticalException("%s can not be read." % mbrtemplate) 756 | 757 | if partition is not None and ((partition < 0) or (partition > 3)): 758 | logging.warning("Cannot activate partition %d", partition) 759 | partition = None 760 | 761 | if ismirbsdmbr: 762 | nmbrbytes = 439 763 | else: 764 | nmbrbytes = 440 765 | 766 | tmpf = tempfile.NamedTemporaryFile() 767 | 768 | logging.debug("executing: dd if='%s' of='%s' bs=512 count=1", device, tmpf.name) 769 | proc = subprocess.Popen( 770 | ["dd", "if=%s" % device, "of=%s" % tmpf.name, "bs=512", "count=1"], 771 | stderr=open(os.devnull, "r+"), 772 | ) 773 | proc.wait() 774 | if proc.returncode != 0: 775 | raise Exception("error executing dd (first run)") 776 | 777 | logging.debug( 778 | "executing: dd if=%s of=%s bs=%s count=1 conv=notrunc", 779 | mbrtemplate, 780 | tmpf.name, 781 | nmbrbytes, 782 | ) 783 | proc = subprocess.Popen( 784 | [ 785 | "dd", 786 | "if=%s" % mbrtemplate, 787 | "of=%s" % tmpf.name, 788 | "bs=%s" % nmbrbytes, 789 | "count=1", 790 | "conv=notrunc", 791 | ], 792 | stderr=open(os.devnull, "r+"), 793 | ) 794 | proc.wait() 795 | if proc.returncode != 0: 796 | raise Exception("error executing dd (second run)") 797 | 798 | mbrcode = tmpf.file.read(512) 799 | if len(mbrcode) < 512: 800 | raise EOFError("MBR size (%d) < 512" % len(mbrcode)) 801 | 802 | if partition is not None: 803 | if ismirbsdmbr: 804 | mbrcode = ( 805 | mbrcode[0:439] 806 | + chr(partition).encode("latin-1") 807 | + mbrcode[440:510] 808 | + b"\x55\xaa" 809 | ) 810 | else: 811 | actives = [b"\x00", b"\x00", b"\x00", b"\x00"] 812 | actives[partition] = b"\x80" 813 | mbrcode = ( 814 | mbrcode[0:446] 815 | + actives[0] 816 | + mbrcode[447:462] 817 | + actives[1] 818 | + mbrcode[463:478] 819 | + actives[2] 820 | + mbrcode[479:494] 821 | + actives[3] 822 | + mbrcode[495:510] 823 | + b"\x55\xaa" 824 | ) 825 | 826 | tmpf.file.seek(0) 827 | tmpf.file.truncate() 828 | tmpf.file.write(mbrcode) 829 | tmpf.file.close() 830 | 831 | set_rw(device) 832 | 833 | logging.debug( 834 | "executing: dd if='%s' of='%s' bs=512 count=1 conv=notrunc,fsync", 835 | tmpf.name, 836 | device, 837 | ) 838 | proc = subprocess.Popen( 839 | [ 840 | "dd", 841 | "if=%s" % tmpf.name, 842 | "of=%s" % device, 843 | "bs=512", 844 | "count=1", 845 | "conv=notrunc,fsync", 846 | ], 847 | stderr=open(os.devnull, "r+"), 848 | ) 849 | proc.wait() 850 | if proc.returncode != 0: 851 | raise Exception("error executing dd (third run)") 852 | del tmpf 853 | 854 | blockdev_args = ["blockdev", "--rereadpt", device] 855 | logging.debug("Probing device using: %s", " ".join(blockdev_args)) 856 | proc = subprocess.Popen(blockdev_args) 857 | proc.wait() 858 | if proc.returncode != 0: 859 | logging.warning( 860 | "Probing device failed with return code: %d (command: %s)", 861 | proc.returncode, 862 | " ".join(blockdev_args), 863 | ) 864 | logging.warning("(Install util-linux?)") 865 | 866 | set_rw(device) 867 | 868 | 869 | def mount(source, target, mount_options): 870 | """Mount specified source on given target 871 | 872 | @source: name of device/ISO that should be mounted 873 | @target: directory where the ISO should be mounted to 874 | @options: mount specific options""" 875 | 876 | # note: options.dryrun does not work here, as we have to 877 | # locate files and identify the grml flavour 878 | 879 | for x in open("/proc/mounts", "r").readlines(): 880 | if x.startswith(source): 881 | raise CriticalException( 882 | ( 883 | "Error executing mount: {0} already mounted - " 884 | "please unmount before invoking grml2usb" 885 | ).format(source) 886 | ) 887 | 888 | if os.path.isdir(source): 889 | logging.debug("Source %s is not a device, therefore not mounting.", source) 890 | return 0 891 | 892 | logging.debug("mount %s %s %s", mount_options, source, target) 893 | proc = subprocess.Popen(["mount"] + list(mount_options) + [source, target]) 894 | proc.wait() 895 | if proc.returncode != 0: 896 | raise CriticalException( 897 | "Error executing mount (no filesystem on the partition?)" 898 | ) 899 | else: 900 | logging.debug("register_mountpoint(%s)", target) 901 | register_mountpoint(target) 902 | 903 | 904 | def unmount(target, unmount_options): 905 | """Unmount specified target 906 | 907 | @target: target where something is mounted on and which should be unmounted 908 | @options: options for umount command""" 909 | 910 | # make sure we unmount only already mounted targets 911 | target_unmount = False 912 | mounts = open("/proc/mounts").readlines() 913 | mountstring = re.compile(".*%s.*" % re.escape(os.path.realpath(target))) 914 | for line in mounts: 915 | if re.match(mountstring, line): 916 | target_unmount = True 917 | 918 | if not target_unmount: 919 | logging.debug("%s not mounted anymore", target) 920 | else: 921 | logging.debug("umount %s %s", list(unmount_options), target) 922 | proc = subprocess.Popen(["umount"] + list(unmount_options) + [target]) 923 | proc.wait() 924 | if proc.returncode != 0: 925 | raise Exception("Error executing umount") 926 | else: 927 | logging.debug("unregister_mountpoint(%s)", target) 928 | unregister_mountpoint(target) 929 | 930 | 931 | def extract_device_name(device): 932 | """Extract the device name of a given path 933 | 934 | @device: device name, like /dev/sda1 or /dev/sda 935 | """ 936 | return re.match(r"/dev/(.*?)\d*$", device).group(1) 937 | 938 | 939 | def check_for_usbdevice(device): 940 | """Check whether the specified device is a removable USB device 941 | 942 | @device: device name, like /dev/sda1 or /dev/sda 943 | """ 944 | 945 | usbdevice = extract_device_name(device) 946 | # newer systems: 947 | usbdev = os.path.realpath("/sys/class/block/" + usbdevice + "/removable") 948 | if not os.path.isfile(usbdev): 949 | # Ubuntu with kernel 2.6.24 for example: 950 | usbdev = os.path.realpath("/sys/block/" + usbdevice + "/removable") 951 | 952 | if os.path.isfile(usbdev): 953 | is_usb = open(usbdev).readline() 954 | if is_usb.find("1"): 955 | return 0 956 | 957 | return 1 958 | 959 | 960 | def check_for_fat(partition): 961 | """Check whether specified partition is a valid FAT filesystem 962 | 963 | @partition: device name of partition""" 964 | 965 | if not os.access(partition, os.R_OK): 966 | raise CriticalException( 967 | "Failed to read device %s" 968 | " (wrong UID/permissions or device/directory not present?)" % partition 969 | ) 970 | 971 | try: 972 | filesystem = ( 973 | subprocess.check_output( 974 | ["/sbin/blkid", "-s", "TYPE", "-o", "value", partition] 975 | ) 976 | .decode() 977 | .rstrip() 978 | ) 979 | 980 | if filesystem != "vfat": 981 | raise CriticalException( 982 | "Partition %s does not contain a FAT filesystem. " 983 | "(Use --format or run mkfs.vfat %s)" % (partition, partition) 984 | ) 985 | 986 | except OSError: 987 | raise CriticalException( 988 | "Sorry, /sbin/blkid not available (install util-linux?)" 989 | ) 990 | 991 | 992 | def mkdir(directory): 993 | """Simple wrapper around os.makedirs to get shell mkdir -p behaviour""" 994 | 995 | # just silently pass as it's just fine it the directory exists 996 | if not os.path.isdir(directory): 997 | try: 998 | os.makedirs(directory) 999 | # pylint: disable-msg=W0704 1000 | except OSError: 1001 | pass 1002 | 1003 | 1004 | def exec_rsync(source, target): 1005 | """Simple wrapper around rsync to install files 1006 | 1007 | @source: source file/directory 1008 | @target: target file/directory""" 1009 | logging.debug("Source: %s / Target: %s", source, target) 1010 | proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", source, target]) 1011 | proc.wait() 1012 | if proc.returncode == 12: 1013 | logging.critical("Fatal: No space left on device") 1014 | cleanup() 1015 | sys.exit(1) 1016 | 1017 | if proc.returncode != 0: 1018 | logging.critical("Fatal: could not install %s", source) 1019 | cleanup() 1020 | sys.exit(1) 1021 | 1022 | 1023 | def write_uuid(target_file): 1024 | """Generates an returns uuid and write it to the specified file 1025 | 1026 | @target_file: filename to write the uuid to 1027 | """ 1028 | 1029 | fileh = open(target_file, "w") 1030 | uid = str(uuid.uuid4()) 1031 | fileh.write(uid) 1032 | fileh.close() 1033 | return uid 1034 | 1035 | 1036 | def get_target_bootid(target): 1037 | """Get the uuid of the specified target. Will generate an uuid if none exist. 1038 | 1039 | @target: directory/mountpoint containing the grml layout 1040 | """ 1041 | 1042 | conf_target = target + "/conf/" 1043 | uuid_file_name = conf_target + "/bootid.txt" 1044 | if os.path.isdir(conf_target): 1045 | if os.path.isfile(uuid_file_name): 1046 | uuid_file = open(uuid_file_name, "r") 1047 | uid = uuid_file.readline().strip() 1048 | uuid_file.close() 1049 | return uid 1050 | else: 1051 | return write_uuid(uuid_file_name) 1052 | else: 1053 | execute(mkdir, conf_target) 1054 | return write_uuid(uuid_file_name) 1055 | 1056 | 1057 | def get_shortname(grml_flavour): 1058 | """Get shortname based from grml_flavour name. The rules applied are the same as in grml-live 1059 | @grml_flavour: flavour name which shold be translated to shortname""" 1060 | 1061 | return re.sub(r"[,._-]", "", grml_flavour) 1062 | 1063 | 1064 | def copy_system_files(grml_flavour, iso_mount, target): 1065 | """copy grml's main files (like squashfs, kernel and initrd) to a given target 1066 | 1067 | @grml_flavour: name of grml flavour the configuration should be generated for 1068 | @iso_mount: path where a grml ISO is mounted on 1069 | @target: path where grml's main files should be copied to""" 1070 | 1071 | squashfs = search_file(grml_flavour + ".squashfs", iso_mount) 1072 | if squashfs is None: 1073 | logging.error("error locating squashfs file") 1074 | raise CriticalException( 1075 | "squashfs file not found, please check that your iso is not corrupt" 1076 | ) 1077 | else: 1078 | squashfs_target = target + "/live/" + grml_flavour + "/" 1079 | execute(mkdir, squashfs_target) 1080 | exec_rsync(squashfs, squashfs_target + grml_flavour + ".squashfs") 1081 | 1082 | for prefix in grml_flavour + "/", "": 1083 | filesystem_module = search_file(prefix + "filesystem.module", iso_mount) 1084 | if filesystem_module: 1085 | break 1086 | if filesystem_module is None: 1087 | logging.error("error locating filesystem.module file") 1088 | raise CriticalException("filesystem.module not found") 1089 | else: 1090 | exec_rsync(filesystem_module, squashfs_target + "filesystem.module") 1091 | 1092 | shortname = get_shortname(grml_flavour) 1093 | if os.path.isdir(iso_mount + "/boot/" + shortname): 1094 | exec_rsync(iso_mount + "/boot/" + shortname, target + "/boot") 1095 | else: 1096 | kernel = search_file("vmlinuz", iso_mount) 1097 | 1098 | if kernel is None: 1099 | logging.error("error locating kernel file") 1100 | raise CriticalException("Kernel not found") 1101 | 1102 | source = os.path.dirname(kernel) + "/" 1103 | dest = target + "/" + os.path.dirname(kernel).replace(iso_mount, "") + "/" 1104 | execute(mkdir, dest) 1105 | exec_rsync(source, dest) 1106 | 1107 | 1108 | def copy_grml_files(grml_flavour, iso_mount, target): 1109 | """copy some minor grml files to a given target 1110 | 1111 | @grml_flavour: the current grml_flavour 1112 | @iso_mount: path where a grml ISO is mounted on 1113 | @target: path where grml's main files should be copied to""" 1114 | 1115 | grml_target = target + "/grml/" 1116 | execute(mkdir, grml_target) 1117 | 1118 | grml_prefixe = ["GRML", "grml"] 1119 | for prefix in grml_prefixe: 1120 | filename = "{0}/{1}/{2}".format(iso_mount, prefix, grml_flavour) 1121 | if os.path.exists(filename): 1122 | exec_rsync(filename, grml_target) 1123 | break 1124 | else: 1125 | logging.warning( 1126 | "Warning: could not find flavour directory for %s ", grml_flavour 1127 | ) 1128 | 1129 | 1130 | def copy_addons(iso_mount, target): 1131 | """copy grml's addons files to a given target 1132 | 1133 | @iso_mount: path where a grml ISO is mounted on 1134 | @target: path where grml's main files should be copied to""" 1135 | 1136 | addons = target + "/boot/addons/" 1137 | execute(mkdir, addons) 1138 | 1139 | for addon_file in glob.glob(iso_mount + "/boot/addons/*"): 1140 | filename = os.path.basename(addon_file) 1141 | src_file = iso_mount + "/boot/addons/" + os.path.basename(addon_file) 1142 | logging.debug("Copying addon file %s" % filename) 1143 | exec_rsync(src_file, addons) 1144 | 1145 | 1146 | def build_loopbackcfg(target): 1147 | """Generate GRUB's loopback.cfg based on existing config files. 1148 | 1149 | @target: target directory 1150 | """ 1151 | 1152 | grub_dir = "/boot/grub/" 1153 | mkdir(os.path.join(target, grub_dir)) 1154 | 1155 | f = open(target + grub_dir + "loopback.cfg", "w") 1156 | 1157 | f.write("# grml2usb generated grub2 configuration file\n") 1158 | f.write("source /boot/grub/header.cfg\n") 1159 | 1160 | for defaults in glob.glob( 1161 | target + os.path.sep + grub_dir + os.path.sep + "*_default.cfg" 1162 | ): 1163 | sourcefile = defaults.split(target + os.path.sep)[1] 1164 | logging.debug("Found source file" + sourcefile) 1165 | os.path.isfile(defaults) and f.write("source " + sourcefile + "\n") 1166 | 1167 | for ops in glob.glob( 1168 | target + os.path.sep + grub_dir + os.path.sep + "*_options.cfg" 1169 | ): 1170 | sourcefile = ops.split(target + os.path.sep)[1] 1171 | logging.debug("Found source file" + sourcefile) 1172 | os.path.isfile(ops) and f.write("source " + sourcefile + "\n") 1173 | 1174 | f.write("source /boot/grub/addons.cfg\n") 1175 | f.write("source /boot/grub/footer.cfg\n") 1176 | f.close() 1177 | 1178 | 1179 | def glob_and_copy(filepattern, dst): 1180 | """Glob on specified filepattern and copy the result to dst 1181 | 1182 | @filepattern: globbing pattern 1183 | @dst: target directory 1184 | """ 1185 | for name in glob.glob(filepattern): 1186 | copy_if_exist(name, dst) 1187 | 1188 | 1189 | def search_and_copy(filename, search_path, dst): 1190 | """Search for the specified filename at searchpath and copy it to dst 1191 | 1192 | @filename: filename to look for 1193 | @search_path: base search file 1194 | @dst: destionation to copy the file to 1195 | """ 1196 | file_location = search_file(filename, search_path) 1197 | copy_if_exist(file_location, dst) 1198 | 1199 | 1200 | def copy_if_exist(filename, dst): 1201 | """Copy filename to dst if filename is set. 1202 | 1203 | @filename: a filename 1204 | @dst: dst file 1205 | """ 1206 | if filename and (os.path.isfile(filename) or os.path.isdir(filename)): 1207 | exec_rsync(filename, dst) 1208 | 1209 | 1210 | def copy_bootloader_files(iso_mount, target, grml_flavour): 1211 | """Copy grml's bootloader files to a given target 1212 | 1213 | @iso_mount: path where a grml ISO is mounted on 1214 | @target: path where grml's main files should be copied to 1215 | @grml_flavour: name of the current processed grml_flavour 1216 | """ 1217 | assert options is not None 1218 | 1219 | grub_target = target + "/boot/grub/" 1220 | execute(mkdir, grub_target) 1221 | 1222 | require_syslinux = options.bootloader == "syslinux" 1223 | logo = search_file("logo.16", iso_mount, required=require_syslinux) 1224 | if logo: 1225 | syslinux_target = target + "/boot/syslinux/" 1226 | execute(mkdir, syslinux_target) 1227 | exec_rsync(logo, syslinux_target + "logo.16") 1228 | else: 1229 | # arm64 ISOs do not suport it 1230 | syslinux_target = None 1231 | 1232 | for filename in ("bootx64.efi", "bootaa64.efi"): 1233 | efi_loader = search_file(filename, iso_mount) 1234 | if efi_loader: 1235 | mkdir(target + "/efi/boot/") 1236 | exec_rsync(efi_loader, target + "/efi/boot/" + filename) 1237 | 1238 | efi_img = search_file("efi.img", iso_mount) 1239 | if efi_img: 1240 | mkdir(target + "/boot/") 1241 | exec_rsync(efi_img, target + "/boot/efi.img") 1242 | handle_secure_boot(target, efi_img) 1243 | 1244 | execute(mkdir, target + "/conf/") 1245 | glob_and_copy(iso_mount + "/conf/bootfile_*", target + "/conf/") 1246 | bootid = get_target_bootid(target) 1247 | 1248 | if not os.path.exists(iso_mount + "/boot/grub/footer.cfg"): 1249 | logging.warning( 1250 | "Warning: Grml releases older than 2011.12 support only one flavour in grub." 1251 | ) 1252 | 1253 | if syslinux_target: 1254 | for ffile in ["f%d" % number for number in range(1, 11)]: 1255 | search_and_copy(ffile, iso_mount, syslinux_target + ffile) 1256 | 1257 | # avoid the "file is read only, overwrite anyway (y/n) ?" question 1258 | # of mtools by syslinux ("mmove -D o -D O s:/ldlinux.sys $target_file") 1259 | if os.path.isfile(syslinux_target + "ldlinux.sys"): 1260 | os.unlink(syslinux_target + "ldlinux.sys") 1261 | 1262 | (source_dir, name) = get_defaults_file(iso_mount, grml_flavour, "default.cfg") 1263 | (source_dir, defaults_file) = get_defaults_file( 1264 | iso_mount, grml_flavour, "grml.cfg" 1265 | ) 1266 | 1267 | if source_dir: 1268 | # Copy syslinux files if they exist on the ISO. arm64 ISOs no longer have them. 1269 | for expr in ( 1270 | name, 1271 | "distri.cfg", 1272 | defaults_file, 1273 | "grml.png", 1274 | "hd.cfg", 1275 | "isolinux.cfg", 1276 | "isolinux.bin", 1277 | "isoprompt.cfg", 1278 | "options.cfg", 1279 | "prompt.cfg", 1280 | "vesamenu.cfg", 1281 | "grml.png", 1282 | "*.c32", 1283 | ): 1284 | glob_and_copy(iso_mount + source_dir + expr, syslinux_target) 1285 | 1286 | for modules_dir in options.syslinuxlibs + SYSLINUX_LIBS: 1287 | if os.path.isdir(modules_dir): 1288 | for filename in glob.glob1(syslinux_target, "*.c32"): 1289 | copy_if_exist( 1290 | os.path.join(modules_dir, filename), syslinux_target 1291 | ) 1292 | break 1293 | 1294 | # copy the addons_*.cfg file to the new syslinux directory 1295 | glob_and_copy(iso_mount + source_dir + "addon*.cfg", syslinux_target) 1296 | 1297 | search_and_copy( 1298 | "hidden.cfg", 1299 | iso_mount + source_dir, 1300 | syslinux_target + "new_" + "hidden.cfg", 1301 | ) 1302 | 1303 | if not options.dryrun: 1304 | handle_syslinux_config(grml_flavour, target, bootid) 1305 | 1306 | else: 1307 | logging.info("Skipping syslinux installation, ISO does not support it") 1308 | 1309 | # copy all grub files from ISO 1310 | glob_and_copy(iso_mount + "/boot/grub/*", grub_target) 1311 | 1312 | # finally (after all GRUB files have been installed) build static loopback.cfg 1313 | build_loopbackcfg(target) 1314 | 1315 | handle_grub_config(grml_flavour, target, bootid) 1316 | 1317 | 1318 | def install_iso_files(grml_flavour, iso_mount, device, target): 1319 | """Copy files from ISO to given target 1320 | 1321 | @grml_flavour: name of grml flavour the configuration should be generated for 1322 | @iso_mount: path where a grml ISO is mounted on 1323 | @device: device/partition where bootloader should be installed to 1324 | @target: path where grml's main files should be copied to""" 1325 | assert options is not None 1326 | 1327 | global GRML_DEFAULT 1328 | GRML_DEFAULT = GRML_DEFAULT or grml_flavour 1329 | if options.dryrun: 1330 | return 0 1331 | elif not options.bootloaderonly: 1332 | logging.info("Copying files. This might take a while....") 1333 | try: 1334 | copy_system_files(grml_flavour, iso_mount, target) 1335 | copy_grml_files(grml_flavour, iso_mount, target) 1336 | except CriticalException as error: 1337 | logging.critical("Execution failed: %s", error) 1338 | sys.exit(1) 1339 | 1340 | if not options.skipaddons: 1341 | if not search_file("addons", iso_mount): 1342 | logging.info("Could not find addons, therefore not installing.") 1343 | else: 1344 | copy_addons(iso_mount, target) 1345 | 1346 | if not options.copyonly: 1347 | copy_bootloader_files(iso_mount, target, grml_flavour) 1348 | 1349 | # make sure we sync filesystems before returning 1350 | logging.info("Synching data (this might take a while)") 1351 | proc = subprocess.Popen(["sync"]) 1352 | proc.wait() 1353 | 1354 | 1355 | def get_device_from_partition(partition): 1356 | device = partition 1357 | partition_number = None 1358 | if partition[-1].isdigit() and not RE_LOOP_DEVICE.match(partition): 1359 | m = RE_P_PARTITION.match(partition) or RE_PARTITION.match(partition) 1360 | if m: 1361 | device = m.group(1) 1362 | partition_number = int(m.group(2)) - 1 1363 | return (device, partition_number) 1364 | 1365 | 1366 | def get_flavour(flavour_str): 1367 | """Returns the flavour of a grml version string""" 1368 | return re.match(r"[\w-]*", flavour_str).group() 1369 | 1370 | 1371 | def identify_grml_flavour(mountpath): 1372 | """Get name of grml flavour 1373 | 1374 | @mountpath: path where the grml ISO is mounted to 1375 | @return: name of grml-flavour""" 1376 | 1377 | version_files = search_file("grml-version", mountpath, lst_return=True) 1378 | 1379 | if not version_files: 1380 | if mountpath.startswith("/run/live/medium"): 1381 | logging.critical("Error: could not find grml-version file.") 1382 | logging.critical( 1383 | "Looks like your system is running from RAM but required files are not available." 1384 | ) 1385 | logging.critical( 1386 | "Please either boot without toram=... or use boot option toram instead of toram=..." 1387 | ) 1388 | else: 1389 | logging.critical("Error: could not find grml-version file.") 1390 | cleanup() 1391 | sys.exit(1) 1392 | 1393 | flavours = [] 1394 | logging.debug("version_files = %s", version_files) 1395 | for version_file in version_files: 1396 | tmpfile = None 1397 | try: 1398 | tmpfile = open(version_file, "r") 1399 | for line in tmpfile.readlines(): 1400 | flavours.append(get_flavour(line)) 1401 | finally: 1402 | if tmpfile: 1403 | tmpfile.close() 1404 | 1405 | return flavours 1406 | 1407 | 1408 | def get_bootoptions(grml_flavour): 1409 | """Returns bootoptions for specific flavour 1410 | 1411 | @grml_flavour: name of the grml_flavour 1412 | """ 1413 | assert options is not None 1414 | # do NOT write "None" in kernel cmdline 1415 | if not options.bootoptions: 1416 | bootopt = "" 1417 | else: 1418 | bootopt = " ".join(options.bootoptions) 1419 | bootopt = bootopt.replace("%flavour", grml_flavour) 1420 | return bootopt 1421 | 1422 | 1423 | def handle_grub_config(grml_flavour, target, bootid): 1424 | """Main handler for generating grub (v1 and v2) configuration 1425 | 1426 | @grml_flavour: name of grml flavour the configuration should be generated for 1427 | @target: path of grub's configuration files 1428 | @bootid: unique id of the target usb key 1429 | """ 1430 | assert options is not None 1431 | 1432 | if options.skipgrubconfig: 1433 | logging.info("Skipping generation of grub configuration as requested.") 1434 | return 1435 | 1436 | logging.debug("Updating grub configuration") 1437 | 1438 | grub_target = target + "/boot/grub/" 1439 | 1440 | bootid_re = re.compile(r"bootid=[\w_-]+") 1441 | live_media_path_re = re.compile(r"live-media-path=[\w_/-]+") 1442 | 1443 | bootopt = get_bootoptions(grml_flavour) 1444 | 1445 | remove_regexes = [] 1446 | option_re = re.compile(r"(.*/boot/.*vmlinuz.*)") 1447 | 1448 | if options.removeoption: 1449 | for regex in options.removeoption: 1450 | remove_regexes.append(re.compile(regex)) 1451 | 1452 | shortname = get_shortname(grml_flavour) 1453 | for filename in glob.glob(grub_target + "*.cfg"): 1454 | for line in fileinput.input(filename, inplace=1): 1455 | line = line.rstrip("\r\n") 1456 | if option_re.search(line): 1457 | line = bootid_re.sub("", line) 1458 | if shortname in filename: 1459 | line = live_media_path_re.sub("", line) 1460 | line = line.rstrip() + " live-media-path=/live/%s/ " % ( 1461 | grml_flavour 1462 | ) 1463 | if bootopt.strip(): 1464 | line = line.replace(" {} ".format(bootopt.strip()), " ") 1465 | if line.endswith(bootopt): 1466 | line = line[: -len(bootopt)] 1467 | line = line.rstrip() + r" bootid=%s %s " % (bootid, bootopt) 1468 | for regex in remove_regexes: 1469 | line = regex.sub(" ", line) 1470 | print(line) 1471 | fileinput.close() 1472 | 1473 | 1474 | def initial_syslinux_config(target): 1475 | """Generates initial syslinux configuration 1476 | 1477 | @target path of syslinux's configuration files""" 1478 | 1479 | target = target + "/" 1480 | filename = target + "grmlmain.cfg" 1481 | if os.path.isfile(target + "grmlmain.cfg"): 1482 | return 1483 | data = open(filename, "w") 1484 | data.write(generate_main_syslinux_config()) 1485 | data.close() 1486 | 1487 | filename = target + "hiddens.cfg" 1488 | data = open(filename, "w") 1489 | data.write("include hidden.cfg\n") 1490 | data.close() 1491 | 1492 | 1493 | def add_entry_if_not_present(filename, entry): 1494 | """Write entry into filename if entry is not already in the file 1495 | 1496 | @filename: name of the file 1497 | @entry: data to write to the file 1498 | """ 1499 | data = open(filename, "a+") 1500 | data.seek(0) 1501 | for line in data: 1502 | if line == entry: 1503 | break 1504 | else: 1505 | data.write(entry) 1506 | 1507 | data.close() 1508 | 1509 | 1510 | def get_flavour_filename(flavour): 1511 | """Generate a iso9960 save filename out of the specified flavour 1512 | 1513 | @flavour: grml flavour 1514 | """ 1515 | return flavour.replace("-", "_") 1516 | 1517 | 1518 | def adjust_syslinux_bootoptions(src, flavour, bootid): 1519 | """Adjust existing bootoptions of specified syslinux config to 1520 | grml2usb specific ones, e.g. change the location of the kernel... 1521 | 1522 | @src: config file to alter 1523 | @flavour: grml flavour 1524 | @bootid: unique id of the target usb key 1525 | """ 1526 | assert options is not None 1527 | 1528 | append_re = re.compile(r"^(\s*append.*/boot/.*)$", re.I) 1529 | # flavour_re = re.compile("(label.*)(grml\w+)") 1530 | default_re = re.compile(r"(default.cfg)") 1531 | bootid_re = re.compile(r"bootid=[\w_-]+") 1532 | live_media_path_re = re.compile(r"live-media-path=[\w_/-]+") 1533 | 1534 | bootopt = get_bootoptions(flavour) 1535 | 1536 | regexe = [] 1537 | option_re = None 1538 | if options.removeoption: 1539 | option_re = re.compile(r"/boot/.*/(initrd.gz|initrd.img)") 1540 | 1541 | for regex in options.removeoption: 1542 | regexe.append(re.compile(r"%s" % regex)) 1543 | 1544 | for line in fileinput.input(src, inplace=1): 1545 | # line = flavour_re.sub(r'\1 %s-\2' % flavour, line) 1546 | line = default_re.sub(r"%s-\1" % flavour, line) 1547 | line = bootid_re.sub("", line) 1548 | line = live_media_path_re.sub("", line) 1549 | line = append_re.sub(r"\1 live-media-path=/live/%s/ " % flavour, line) 1550 | line = append_re.sub(r"\1 boot=live %s " % bootopt, line) 1551 | line = append_re.sub(r"\1 bootid=%s " % bootid, line) 1552 | if option_re and option_re.search(line): 1553 | for regex in regexe: 1554 | line = regex.sub(" ", line) 1555 | sys.stdout.write(line) 1556 | fileinput.close() 1557 | 1558 | 1559 | def adjust_labels(src, replacement): 1560 | """Adjust the specified labels in the syslinux config file src with 1561 | specified replacement 1562 | """ 1563 | label_re = re.compile(r"^(\s*label\s*) ([a-zA-Z0-9_-]+)", re.I) 1564 | for line in fileinput.input(src, inplace=1): 1565 | line = label_re.sub(replacement, line) 1566 | sys.stdout.write(line) 1567 | fileinput.close() 1568 | 1569 | 1570 | def add_syslinux_entry(filename, grml_flavour): 1571 | """Add includes for a specific grml_flavour to the specified filename 1572 | 1573 | @filename: syslinux config file 1574 | @grml_flavour: grml flavour to add 1575 | """ 1576 | 1577 | entry_filename = "option_%s.cfg" % grml_flavour 1578 | entry = "include %s\n" % entry_filename 1579 | 1580 | add_entry_if_not_present(filename, entry) 1581 | path = os.path.dirname(filename) 1582 | 1583 | data = open(path + "/" + entry_filename, "w") 1584 | data.write(generate_flavour_specific_syslinux_config(grml_flavour)) 1585 | data.close() 1586 | 1587 | 1588 | def modify_filenames(grml_flavour, target, filenames): 1589 | """Replace the standard filenames with the new ones 1590 | 1591 | @grml_flavour: grml-flavour strin 1592 | @target: directory where the files are located 1593 | @filenames: list of filenames to alter 1594 | """ 1595 | grml_filename = get_flavour_filename(grml_flavour) 1596 | for filename in filenames: 1597 | old_filename = "%s/%s" % (target, filename) 1598 | new_filename = "%s/%s_%s" % (target, grml_filename, filename) 1599 | os.rename(old_filename, new_filename) 1600 | 1601 | 1602 | def remove_default_entry(filename): 1603 | """Remove the default entry from specified syslinux file 1604 | 1605 | @filename: syslinux config file 1606 | """ 1607 | default_re = re.compile(r"^(\s*menu\s*default\s*)$", re.I) 1608 | for line in fileinput.input(filename, inplace=1): 1609 | if default_re.match(line): 1610 | continue 1611 | sys.stdout.write(line) 1612 | fileinput.close() 1613 | 1614 | 1615 | def handle_syslinux_config(grml_flavour, target, bootid): 1616 | """Main handler for generating syslinux configuration 1617 | 1618 | @grml_flavour: name of grml flavour the configuration should be generated for 1619 | @target: path of syslinux's configuration files 1620 | @bootid: unique id of the target usb key 1621 | """ 1622 | assert options is not None 1623 | 1624 | if options.skipsyslinuxconfig: 1625 | logging.info("Skipping generation of syslinux configuration as requested.") 1626 | return 1627 | 1628 | syslinux_target = target + "/boot/syslinux/" 1629 | logging.debug("Generating syslinux configuration in %s", syslinux_target) 1630 | if not os.path.exists(syslinux_target): 1631 | logging.info("Skipping syslinux configuration, ISO does not support it") 1632 | return 1633 | 1634 | syslinux_cfg = syslinux_target + "syslinux.cfg" 1635 | 1636 | # install main configuration only *once*, no matter how many ISOs we have: 1637 | syslinux_config_file = open(syslinux_cfg, "w") 1638 | syslinux_config_file.write("timeout 300\n") 1639 | syslinux_config_file.write("include vesamenu.cfg\n") 1640 | syslinux_config_file.close() 1641 | 1642 | prompt_name = open(syslinux_target + "promptname.cfg", "w") 1643 | prompt_name.write("menu label S^yslinux prompt\n") 1644 | prompt_name.close() 1645 | 1646 | initial_syslinux_config(syslinux_target) 1647 | flavour_filename = get_flavour_filename(grml_flavour) 1648 | 1649 | if search_file("default.cfg", syslinux_target): 1650 | modify_filenames(grml_flavour, syslinux_target, ["grml.cfg", "default.cfg"]) 1651 | 1652 | filename = search_file("new_hidden.cfg", syslinux_target) 1653 | 1654 | # process hidden file 1655 | if not search_file("hidden.cfg", syslinux_target): 1656 | new_hidden = syslinux_target + "hidden.cfg" 1657 | os.rename(filename, new_hidden) 1658 | adjust_syslinux_bootoptions(new_hidden, grml_flavour, bootid) 1659 | else: 1660 | new_hidden_file = "%s/%s_hidden.cfg" % (syslinux_target, flavour_filename) 1661 | os.rename(filename, new_hidden_file) 1662 | adjust_labels(new_hidden_file, r"\1 %s-\2" % grml_flavour) 1663 | adjust_syslinux_bootoptions(new_hidden_file, grml_flavour, bootid) 1664 | entry = "include %s_hidden.cfg\n" % flavour_filename 1665 | add_entry_if_not_present("%s/hiddens.cfg" % syslinux_target, entry) 1666 | 1667 | new_default = "%s_default.cfg" % (flavour_filename) 1668 | entry = "include %s\n" % new_default 1669 | defaults_file = "%s/defaults.cfg" % syslinux_target 1670 | new_default_with_path = "%s/%s" % (syslinux_target, new_default) 1671 | new_grml_cfg = "%s/%s_grml.cfg" % (syslinux_target, flavour_filename) 1672 | 1673 | if os.path.isfile(defaults_file): 1674 | # remove default menu entry in menu 1675 | remove_default_entry(new_default_with_path) 1676 | 1677 | # adjust all labels for additional isos 1678 | adjust_labels(new_default_with_path, r"\1 %s" % grml_flavour) 1679 | adjust_labels(new_grml_cfg, r"\1 %s-\2" % grml_flavour) 1680 | 1681 | # always adjust bootoptions 1682 | adjust_syslinux_bootoptions(new_default_with_path, grml_flavour, bootid) 1683 | adjust_syslinux_bootoptions(new_grml_cfg, grml_flavour, bootid) 1684 | 1685 | add_entry_if_not_present("%s/defaults.cfg" % syslinux_target, entry) 1686 | 1687 | add_syslinux_entry("%s/additional.cfg" % syslinux_target, flavour_filename) 1688 | 1689 | 1690 | def handle_secure_boot(target, efi_img): 1691 | """Provide secure boot support by extracting files from /boot/efi.img 1692 | 1693 | @target: path where grml's main files should be copied to 1694 | @efi_img: path to the efi.img file that includes the files for secure boot 1695 | """ 1696 | assert options is not None 1697 | 1698 | mkdir(target + "/efi/boot/") 1699 | efi_mountpoint = tempfile.mkdtemp( 1700 | prefix="grml2usb", dir=os.path.abspath(options.tmpdir) 1701 | ) 1702 | logging.debug("efi_mountpoint = %s" % efi_mountpoint) 1703 | register_tmpfile(efi_mountpoint) 1704 | 1705 | try: 1706 | logging.debug( 1707 | "mount(%s, %s, ['-o', 'ro', '-t', 'vfat']" % (efi_img, efi_mountpoint) 1708 | ) 1709 | mount(efi_img, efi_mountpoint, ["-o", "ro", "-t", "vfat"]) 1710 | except CriticalException as error: 1711 | logging.critical("Fatal: %s", error) 1712 | sys.exit(1) 1713 | 1714 | grub_cfg = search_file("grub.cfg", efi_mountpoint + "/boot/grub/") 1715 | logging.debug("grub_cfg = %s" % grub_cfg) 1716 | if not grub_cfg: 1717 | logging.info( 1718 | "No /boot/grub/grub.cfg found inside EFI image, looks like Secure Boot support is missing." 1719 | ) 1720 | else: 1721 | mkdir(target + "/boot/grub/x86_64-efi/") 1722 | logging.debug( 1723 | "exec_rsync(%s, %s + '/boot/grub/x86_64-efi/grub.cfg')" % (grub_cfg, target) 1724 | ) 1725 | exec_rsync(grub_cfg, target + "/boot/grub/x86_64-efi/grub.cfg") 1726 | 1727 | logging.debug( 1728 | "exec_rsync(%s + '/EFI/BOOT/grubx64.efi', %s + '/efi/boot/grubx64.efi')'" 1729 | % (efi_mountpoint, target) 1730 | ) 1731 | exec_rsync( 1732 | efi_mountpoint + "/EFI/BOOT/grubx64.efi", target + "/efi/boot/grubx64.efi" 1733 | ) 1734 | 1735 | # NOTE - we're overwriting /efi/boot/bootx64.efi from copy_bootloader_files here 1736 | logging.debug( 1737 | "exec_rsync(%s + '/EFI/BOOT/bootx64.efi', %s + '/efi/boot/bootx64.efi')'" 1738 | % (efi_mountpoint, target) 1739 | ) 1740 | exec_rsync( 1741 | efi_mountpoint + "/EFI/BOOT/bootx64.efi", target + "/efi/boot/bootx64.efi" 1742 | ) 1743 | 1744 | try: 1745 | unmount(efi_mountpoint, "") 1746 | logging.debug("Unmounted %s" % efi_mountpoint) 1747 | os.rmdir(efi_mountpoint) 1748 | logging.debug("Removed directory %s" % efi_mountpoint) 1749 | except Exception: 1750 | logging.critical("RuntimeError while umount %s" % efi_mountpoint) 1751 | sys.exit(1) 1752 | 1753 | 1754 | def install(image, device): 1755 | """Install a grml image to the specified device 1756 | 1757 | @image: directory or is file 1758 | @device: partition or directory to install the device 1759 | """ 1760 | assert options is not None 1761 | iso_mountpoint = image 1762 | remove_image_mountpoint = False 1763 | if os.path.isdir(image): 1764 | if options.force or os.path.exists(os.path.join(image, "live")): 1765 | logging.info("Using %s as install base", image) 1766 | else: 1767 | q = input( 1768 | "%s does not look like a Grml system. " 1769 | "Do you really want to use this image? y/N " % image 1770 | ) 1771 | if q.lower() == "y": 1772 | logging.info("Using %s as install base", image) 1773 | else: 1774 | logging.info("Skipping install base %s", image) 1775 | else: 1776 | logging.info("Using ISO %s", image) 1777 | iso_mountpoint = tempfile.mkdtemp( 1778 | prefix="grml2usb", dir=os.path.abspath(options.tmpdir) 1779 | ) 1780 | register_tmpfile(iso_mountpoint) 1781 | remove_image_mountpoint = True 1782 | try: 1783 | mount(image, iso_mountpoint, ["-o", "loop,ro", "-t", "iso9660"]) 1784 | except CriticalException as error: 1785 | logging.critical("Fatal: %s", error) 1786 | sys.exit(1) 1787 | 1788 | try: 1789 | install_grml(iso_mountpoint, device) 1790 | finally: 1791 | if remove_image_mountpoint: 1792 | try: 1793 | remove_mountpoint(iso_mountpoint) 1794 | except CriticalException: 1795 | cleanup() 1796 | raise 1797 | 1798 | 1799 | def install_grml(mountpoint, device): 1800 | """Main logic for copying files of the currently running Grml system. 1801 | 1802 | @mountpoint: directory where currently running live system resides (usually /run/live/medium) 1803 | @device: partition where the specified ISO should be installed to""" 1804 | 1805 | device_mountpoint = device 1806 | if os.path.isdir(device): 1807 | logging.info("Specified device is a directory, therefore not mounting.") 1808 | remove_device_mountpoint = False 1809 | else: 1810 | device_mountpoint = tempfile.mkdtemp(prefix="grml2usb") 1811 | register_tmpfile(device_mountpoint) 1812 | remove_device_mountpoint = True 1813 | try: 1814 | set_rw(device) 1815 | mount(device, device_mountpoint, ["-o", "utf8,iocharset=iso8859-1"]) 1816 | except CriticalException: 1817 | mount(device, device_mountpoint, "") 1818 | try: 1819 | grml_flavours = identify_grml_flavour(mountpoint) 1820 | for flavour in set(grml_flavours): 1821 | if not flavour: 1822 | logging.warning("No valid flavour found, please check your iso") 1823 | logging.info('Identified grml flavour "%s".', flavour) 1824 | install_iso_files(flavour, mountpoint, device, device_mountpoint) 1825 | GRML_FLAVOURS.add(flavour) 1826 | finally: 1827 | if remove_device_mountpoint: 1828 | remove_mountpoint(device_mountpoint) 1829 | 1830 | 1831 | def remove_mountpoint(mountpoint): 1832 | """remove a registered mountpoint""" 1833 | 1834 | try: 1835 | unmount(mountpoint, "") 1836 | if os.path.isdir(mountpoint): 1837 | os.rmdir(mountpoint) 1838 | unregister_tmpfile(mountpoint) 1839 | except CriticalException: 1840 | cleanup() 1841 | raise 1842 | 1843 | 1844 | def handle_mbr(device): 1845 | """Main handler for installing master boot record (MBR) 1846 | 1847 | @device: device where the MBR should be installed to""" 1848 | assert options is not None 1849 | 1850 | if options.dryrun: 1851 | logging.info("Would install MBR") 1852 | return 0 1853 | 1854 | mbr_device, partition_number = get_device_from_partition(device) 1855 | if partition_number is None: 1856 | logging.warning("Could not detect partition number, not activating partition") 1857 | 1858 | # if we get e.g. /dev/loop1 as device we don't want to put the MBR 1859 | # into /dev/loop of course, therefore use /dev/loop1 as mbr_device 1860 | if mbr_device == "/dev/loop": 1861 | mbr_device = device 1862 | logging.info( 1863 | "Detected loop device - using %s as MBR device therefore", mbr_device 1864 | ) 1865 | 1866 | mbrcode = GRML2USB_BASE + "/mbr/mbrldr" 1867 | if options.syslinuxmbr: 1868 | mbrcode = "" 1869 | mbr_locations = ( 1870 | "/usr/lib/syslinux/mbr.bin", 1871 | "/usr/lib/syslinux/bios/mbr.bin", 1872 | "/usr/share/syslinux/mbr.bin", 1873 | ) 1874 | for mbrpath in mbr_locations: 1875 | if os.path.isfile(mbrpath): 1876 | mbrcode = mbrpath 1877 | break 1878 | 1879 | if not mbrcode: 1880 | str_locations = " or ".join(['"%s"' % x for x in mbr_locations]) 1881 | logging.error("Cannot find syslinux MBR, install it at %s)", str_locations) 1882 | raise CriticalException( 1883 | "syslinux MBR can not be found at %s." % str_locations 1884 | ) 1885 | elif options.mbrmenu: 1886 | mbrcode = GRML2USB_BASE + "/mbr/mbrldr" 1887 | 1888 | try: 1889 | install_mbr(mbrcode, mbr_device, partition_number, True) 1890 | except (IOError, Exception) as error: 1891 | logging.critical("Execution failed: %s", error) 1892 | sys.exit(1) 1893 | 1894 | 1895 | def handle_vfat(device): 1896 | """Check for FAT specific settings and options 1897 | 1898 | @device: device that should checked / formated""" 1899 | assert options is not None 1900 | 1901 | # make sure we have mkfs.vfat available 1902 | if options.format: 1903 | if not which("mkfs.vfat") and not options.copyonly and not options.dryrun: 1904 | logging.critical("Sorry, mkfs.vfat not available. Exiting.") 1905 | logging.critical("Please make sure to install dosfstools.") 1906 | sys.exit(1) 1907 | 1908 | if options.force: 1909 | print("Forcing mkfs.vfat on %s as requested via option --force." % device) 1910 | else: 1911 | # make sure the user is aware of what he is doing 1912 | f = input("Are you sure you want to format the specified partition? y/N ") 1913 | if f == "y" or f == "Y": 1914 | logging.info( 1915 | "Note: you can skip this question using the option --force" 1916 | ) 1917 | else: 1918 | sys.exit(1) 1919 | try: 1920 | mkfs_vfat(device) 1921 | except CriticalException as error: 1922 | logging.critical("Execution failed: %s", error) 1923 | sys.exit(1) 1924 | 1925 | # check for fat filesystem 1926 | if ( 1927 | device is not None 1928 | and not os.path.isdir(device) 1929 | and options.bootloader in ("syslinux", "efi") 1930 | ): 1931 | try: 1932 | check_for_fat(device) 1933 | except CriticalException as error: 1934 | logging.critical("Execution failed: %s", error) 1935 | sys.exit(1) 1936 | 1937 | if options.skipusbcheck: 1938 | logging.info( 1939 | "Not checking for removable USB device as requested via option --skip-usb-check." 1940 | ) 1941 | return 1942 | 1943 | if ( 1944 | not os.path.isdir(device) 1945 | and not check_for_usbdevice(device) 1946 | and not options.force 1947 | ): 1948 | print( 1949 | "Warning: the specified device %s does not look like a removable usb device." 1950 | % device 1951 | ) 1952 | f = input("Do you really want to continue? y/N ") 1953 | if f.lower() != "y": 1954 | sys.exit(1) 1955 | 1956 | 1957 | def handle_logging(): 1958 | """Log handling and configuration""" 1959 | assert options is not None 1960 | 1961 | if options.verbose and options.quiet: 1962 | parser.error("please use either verbose (--verbose) or quiet (--quiet) option") 1963 | 1964 | FORMAT = "%(message)s" 1965 | if options.verbose: 1966 | FORMAT = "%(asctime)-15s %(message)s" 1967 | logging.basicConfig(level=logging.DEBUG, format=FORMAT) 1968 | elif options.quiet: 1969 | logging.basicConfig(level=logging.CRITICAL, format=FORMAT) 1970 | else: 1971 | logging.basicConfig(level=logging.INFO, format=FORMAT) 1972 | 1973 | 1974 | def handle_bootloader(device): 1975 | """wrapper for installing bootloader 1976 | 1977 | @device: device where bootloader should be installed to""" 1978 | assert options is not None 1979 | 1980 | # Install bootloader only if not using the --copy-only option 1981 | if options.copyonly: 1982 | logging.info( 1983 | "Not installing bootloader and its files as requested via option copyonly." 1984 | ) 1985 | elif os.path.isdir(device): 1986 | logging.info("Not installing bootloader as %s is a directory.", device) 1987 | else: 1988 | install_bootloader(device) 1989 | 1990 | 1991 | @functools.cache 1992 | def host_architecture() -> str: 1993 | return run_program(["uname", "-m"], capture_output=True).stdout.decode().strip() 1994 | 1995 | 1996 | def check_options(options: argparse.Namespace): 1997 | """ 1998 | Check compatibility of user-provided options, and pick correct default bootloader 1999 | """ 2000 | global GRUB_INSTALL 2001 | GRUB_INSTALL = which("grub-install") or which("grub2-install") 2002 | syslinux_program = which("syslinux") 2003 | 2004 | if options.bootloader == "auto": 2005 | if host_architecture() == "arm64": 2006 | options.bootloader = "efi" 2007 | else: 2008 | if syslinux_program: 2009 | logging.info("Choosing syslinux as bootloader") 2010 | options.bootloader = "syslinux" 2011 | elif GRUB_INSTALL: 2012 | logging.info("Choosing GRUB as bootloader (syslinux not found)") 2013 | options.bootloader = "grub" 2014 | else: 2015 | logging.warning("Choosing EFI-boot as no x86 bootloaders were found") 2016 | logging.warning("Install syslinux and/or grub-install if needed") 2017 | options.bootloader = "efi" 2018 | 2019 | if options.grubmbr and options.bootloader != "grub": 2020 | raise CriticalException("--grub-mbr requires --grub option.") 2021 | 2022 | if options.copyonly and options.bootloader == "grub": 2023 | raise CriticalException("Cannot use --copy-only and --grub at the same time.") 2024 | 2025 | if options.bootloader == "grub": 2026 | if not GRUB_INSTALL: 2027 | logging.critical( 2028 | "Fatal: grub-install not available (please install the " 2029 | "grub package or drop the --grub option)" 2030 | ) 2031 | sys.exit(1) 2032 | else: 2033 | logging.info("Using %s as bootloader", options.bootloader) 2034 | 2035 | elif options.bootloader == "syslinux": 2036 | if not syslinux_program: 2037 | logging.critical( 2038 | "Fatal: syslinux not available (please install the " 2039 | "syslinux package or use the --grub option)" 2040 | ) 2041 | sys.exit(1) 2042 | else: 2043 | logging.info("Using %s as bootloader", options.bootloader) 2044 | 2045 | if not which("rsync"): 2046 | logging.critical("Fatal: rsync not available, can not continue - sorry.") 2047 | sys.exit(1) 2048 | 2049 | 2050 | def load_loop(): 2051 | """Runs modprobe loop and throws away its output""" 2052 | if not which("modprobe"): 2053 | logging.critical("Fatal: modprobe not available, can not continue - sorry.") 2054 | logging.critical("Hint: is /sbin missing in PATH?") 2055 | sys.exit(1) 2056 | 2057 | proc = subprocess.Popen( 2058 | ["modprobe", "loop"], stdout=subprocess.PIPE, stderr=subprocess.PIPE 2059 | ) 2060 | proc.communicate() 2061 | 2062 | 2063 | def main(grml2usb_options: argparse.Namespace): 2064 | """Main invocation""" 2065 | global options 2066 | 2067 | # allow overriding options from a test 2068 | options = grml2usb_options 2069 | 2070 | # log handling 2071 | handle_logging() 2072 | 2073 | logging.info("Executing grml2usb version %s", PROG_VERSION) 2074 | 2075 | # make sure we have the appropriate permissions 2076 | check_uid_root() 2077 | 2078 | check_options(options) 2079 | 2080 | load_loop() 2081 | 2082 | if options.dryrun: 2083 | logging.info("Running in simulation mode as requested via option dry-run.") 2084 | 2085 | # specified arguments 2086 | device = os.path.realpath(options.device) 2087 | 2088 | if not os.path.isdir(device): 2089 | if device[-1:].isdigit(): 2090 | if int(device[-1:]) > 4 or device[-2:].isdigit(): 2091 | logging.warning( 2092 | "Warning: installing on partition number >4, booting *might* fail depending on your system." 2093 | ) 2094 | 2095 | if not options.skipbootflag: 2096 | check_boot_flag(device) 2097 | 2098 | # check for fat partition 2099 | handle_vfat(device) 2100 | 2101 | # main operation (like installing files) 2102 | for iso in options.isos: 2103 | install(iso, device) 2104 | 2105 | # install mbr 2106 | is_superfloppy = not device[-1:].isdigit() 2107 | if is_superfloppy: 2108 | logging.info("Detected superfloppy format - not installing MBR") 2109 | 2110 | if not options.skipmbr and not os.path.isdir(device) and not is_superfloppy: 2111 | handle_mbr(device) 2112 | 2113 | handle_bootloader(device) 2114 | 2115 | logging.info( 2116 | "Note: grml flavour %s was installed as the default booting system.", 2117 | GRML_DEFAULT, 2118 | ) 2119 | 2120 | for flavour in GRML_FLAVOURS: 2121 | logging.info( 2122 | "Note: you can boot flavour %s using '%s' on the commandline.", 2123 | flavour, 2124 | flavour, 2125 | ) 2126 | 2127 | # finally be polite :) 2128 | logging.info( 2129 | "Finished execution of grml2usb (%s). Have fun with your Grml system.", 2130 | PROG_VERSION, 2131 | ) 2132 | 2133 | 2134 | if __name__ == "__main__": 2135 | _options = parser.parse_args() 2136 | try: 2137 | main(_options) 2138 | except KeyboardInterrupt: 2139 | logging.info("Received KeyboardInterrupt") 2140 | cleanup() 2141 | except Exception as error: 2142 | logging.critical("Fatal: %s", str(error)) 2143 | if _options.verbose: 2144 | logging.exception("Exception:") 2145 | sys.exit(1) 2146 | 2147 | # END OF FILE ################################################################## 2148 | # vim:foldmethod=indent expandtab ai ft=python tw=120 fileencoding=utf-8 2149 | --------------------------------------------------------------------------------