Building on the shoulders of giants, I used this information along with others to create a step-by-step HOWTO build an image on any system device.
It is documented to the 9’s. It includes a short one-liner shell command that will take this long-ass description and turn it into a short (~32 command) script that you can run and answer two questions and it will do everything for you.
This is a draft. Please remember that your time is valuable to you, as is mine to me. I contribute so others may be helped – as I have been by the posts above and elsewhere. There will be a final draft when I get back to it.
I always include WHY something is done. Anyone can copy/paste a script, run it once, and forget all about it. Mine come with documentation. I also talk about failures. Yeah, those. When something I’ve done is not the right/best answer I’ll discuss it frankly in the documentation with Future-Me™, you folks, and then when Future-Me fixes it, I won’t remove that mistake… because leaving it in is helpful to Future-Yous knowing WHY I needed to do X, WHAT I tried, and HOW I eventually got X to work. If you follow that, you will take no bad turns onto bad roads that don’t lead to your destination.
Hopefully the formatting will not destroy itself.
Date and times are there for my keeping track of what I did when. They can be safely ignored except if you want to comment that I don’t seem to sleep much or that I haven’t touched it in like 10d 
I hope this is helpful or instructive. I still need to work on the boot scripts (see parent topic) and make them a little better, like building for a USB stick. Also and not related, I’d like to get this on a working USB stick my way, so I can also put a full build environment, and have the SCREEN LIGHT UP AND SHOW SOMETHING when the SOC is up, not when the Linux kernel is already 1/2 the way up…
If there’s something you don’t like about it, speak up. If you see an improvement opportunity, speak up. I didn’t say my code was perfect, and i’d rather share the success with others on 100% solid code than be the sole developer on bad code.
— script follows —
cat /tmp/t2.t | sed -e “s/http/HYPERTEXT/g” -e “s/.com/DOTCOM/g” -e “s/.net/DOTNET/g”
202209211739MST
The goal is to build a bootable USB SDD. Later we’ll do both an NVME and a
multiboot USB. That latter may be difficult if we can’t get a bootloader that
supports menu options to work on the SOC.
This is a detailed explanation of ALL the steps, and why we do them. There is a
script that parses THIS explanation into copy/paste steps:
First, copy THIS entire page into the_text_file, then run the following (copy/paste it) to get
the commands to copy/paste and create the drive.
echo ‘#!/bin/bash -xv’ > script.sh && chmod o+x script.sh
egrep “^> # [[:alpha:]]” the_text_file | sed -e “s/^> # //g” >> script.sh && echo “Run ./script.sh to install.”
Starting Link I used to get all the steps right:
HYPERTEXTs://mauromoralesDOTCOM/2021/05/11/running-mnt-reform-os-on-an-nvme-disk/
CREDIT: Mauro has an excellent tutorial but it skips around a bit, naming something ‘crypt’ in
some areas and ‘reform_crypt’ in others… making assumptions, ignoring previous states.
His use of the right commands are correct, but there’s no explanation of “why”.
This attempts to correct all that. TAKE HEED - HIS STUFF IS EXCELLENT AND SAVED ME
HOURS so credit where credit is due. Thanks, Mauro.
Legend:
Everything that starts with a ‘#’ is an operation at the root command line interface (CLI).
Everything that starts with a ‘$’ is an operation that doesn’t require root access at the CLI.
Everything that’s numbered includes steps to complete an operation.
Everything that starts with an ‘X’ is an op no longer used but education in keeping here.
Everything else is just meandering comments.
Means “Hey come back to this later and answer the question we don’t know the answer to at this point.”
NOTES:
-
Step 8 is a script that turns this article into a copy and paste shell script to do it all for you. You get to set one parameter, and you pick an encryption phrase. It has been copied up top.
-
We want to use full-disk encryption. Mauro used two partitions, /root and /home. We end up with one drive with one partition and we encrypt it into one Physical Volume (PV). On that we have one Volume Group (VG) and on it we have two Logical Volumes (LVs), one ‘root’ which is the root disk partition (‘/’), and one swap which also works as the suspend-to partition. There’s no right way or wrong way. This method is the same as the one used by Linux Mint’s installer. Mint creates vgmint with vgmint-root and vgmint-swap underneath. We do the same with reformvg-root and reformvg-swap.
-
TODOs:
a. DONE: Possibly ask for DEV in a prompt or try and figure it out programmatically. This one is so hard of a problem even the Ubuntu-based installers all offer to unmount the USB drive you’re installing from… they can’t tell it’s not a local disk that shouldn’t be unmounted! Google has a different philosophy with their “Flex” aka renev aka NeverReady ChromeOS for PCs… where if it has a removable medium they disallow its use. That won’t work for us either. SO right now hardcoded DEV=something.
b. See if it will work if we add ‘–exclude=/run --exclude=/proc’ from the rsync. Seriously those are so dynamically created why bother…
c. Remove previous swapfile entries from fstab. We can easily do this but this won’t handle multiple swaps on a system. So we’ll just leave the old ones commented out and make it the user’s problem.
Used gnome-disks but converted to ‘sgdisk’ to keep it in the CLI, faster, and scriptable. If you want to use graphical use 1b instead of 1a.
1a1. Replace DEV with the device you are working with. Examples DEV=/dev/sda1 , DEV=/dev/nvme0n1p1 , etc. Don’t know which? Unplug and replug new drive… then ‘dmesg’ to see what got unplugged and replugged.
DEV=$1; while [ ! -b “$DEV” ]; do if [ ! -z $DEV ]; then echo “Error: $DEV is not a block device.” ; fi; read -p "Target Device: " DEV ; done
1a2. Make sure it’s not mapped from a previous attempt (same as 2h5). Check if LUKS left things mapped and if so unmap so we can be consistent about where we want it. -r so we undo them in reverse order that they were formed
for dm in ls -1r /dev/mapper | grep -v control
; do echo “Unmapping $dm” ; cryptsetup luksClose /dev/mapper/$dm ; done
1a3. Store the encryption phrase for this script only so we don’t ask and reask for it
read -s -p "Encryption passphrase (script use only): " PASS
1a4. We used to use gnome-disks but it’s graphical and not easy to script. Use ‘sgdisk’ instead. Start by new GPT (GUID Partition Table)
sgdisk $DEV -o
1a5. Now the partition creation.
sgdisk $DEV -n 1
1a6. Then ensure LUKS doesn’t have it mapped.
if [ -b “/dev/mapper/crypt” ]; then cryptsetup luksClose /dev/mapper/crypt; fi
1a7. Make it Ext4 to start.
echo “y” | mkfs.ext4 $DEV
1a8. Encrypt it. Use a short password for testing. It’s easy to change later. See Step ###
echo “$PASS” | cryptsetup -q -v luksFormat --type luks2 $DEV
1b. DEPRECATED. ALTERNATE, Graphical method: Start with the physical partition. Use INSTEAD of 1a if you want graphical. Can run after 1a with no ill effects.
1b1. Replace DEV with the device you are working with. Examples DEV=/dev/sda1 , DEV=/dev/nvme0n1p1 , etc. Don’t know which? Unplug and replug new drive… then ‘dmesg’ to see what got unplugged and replugged.
DEV=/dev/sda1
1b2. Install necessary modules to enable LUKS2 for gnome-disks but we ended up using sgdisk so maybe not needed – test ###
apt install -y libblockdev-crypto2 && systemctl restart udisks2.service Note: If you don’t do this what will happen is it will start, mess up the volume, and show this:
bd_crypto_luks_format_luks2_blob called, but not implemented! (udisks-error-quark, 0) Thanks to ‘nicktux’ at Launchpad bugs: HYPERTEXTs://bugs.launchpadDOTNET/ubuntu/+source/meta-gnome3/+bug/1761995/comments/10 for the Ubuntu fix from 2018.
1b3. Hit ‘+’, Create Partition and click Next to use entire volume
1b4. Select “internal use with Linux systems only (Ext4)” and check “Password protect volume (LUKS)” and click Next
1b5. Enter the same password in both fields and click create. For testing purposes we use a short easy password. It’s trivial to change that later. ###
- Get the system partition stuff set up on that
Here’s where Mauro says to use ‘reform-migrate’ but when run it tells you to encrypt stuff to use ‘reform-setup-encrypted-nvme’.
So… we’ll just do what that script does without being too verbose or making the user copy/paste. Hey, you just reformatted a device,
so what other damage do you expect to do?
2a. Create the Physical Volume
2a1. Unlock and map it
echo “$PASS” | cryptsetup luksOpen $DEV crypt
2a2. Create the PV
pvcreate -y /dev/mapper/crypt
The ‘-y’ is to allow wiping the original Ext4 signature. If we don’t add the ‘-y’ we’ll see this warning:
WARNING: ext4 signature detected on /dev/mapper/crypt at offset 1080. Wipe it? [y/n]: n
Aborted wiping of ext4.
1 existing signature left on the device.
2b. Create the Virtual Group
vgcreate reformvg /dev/mapper/crypt
2c, Ad put the logical volume in it
lvcreate --name swap --size 8G reformvg
2d. And the root volume
lvcreate --name root -l 100%FREE reformvg
2e. Make sure a previous version of us didn’t leave root mounted
if [ ! -z “findmnt --source /dev/mapper/reformvg-root
” ]; then umount -f /dev/mapper/reformvg-root; fi
2f. Create the filesystem on the root LV of the reformvg VG on the crypt PV on partition 1 of $DEV
mkfs.ext4 /dev/reformvg/root
2g. Make the swapfile on the swap LV of the reformvg VG on the crypt PV on partition 1 of $DEV
mkswap /dev/reformvg/swap
2h. Get the logical volume all setup for storing suspend data on ‘swap’ and being able to mount it as well
2h1. Set some variables for cleaner look
SWAPUUID=$(blkid -s UUID -o value /dev/reformvg/swap) && CRYPTUUID=$(blkid -s UUID -o value $DEV)
2h2. Tell the boot process where the swap partition, which is where ‘suspend’ mode is saved, so we can resume from it
echo RESUME=UUID=$SWAPUUID > /etc/initramfs-tools/conf.d/resume
2h3. Tell the cryptography system which UUID (references the drive $DEV) has the name “crypt”
echo crypt UUID=$CRYPTUUID none luks,discard > /etc/crypttab
2h4. Tell the filesystem where to mount the /swap partition (for swapping once we’re not suspended)
We’ll have to come back here and remove any other appended (‘>>’) lines.
cp /etc/fstab /etc/fstab.old && grep -v swap.sw /etc/fstab.old > /etc/fstab && echo UUID=$SWAPUUID none swap sw 0 0 >> /etc/fstab && grep swap.sw /etc/fstab.old | sort -u | grep -v UUID=.none | awk ‘{print "### "$0}’ >> /etc/fstab
2h5. Check if LUKS left things mapped and if so unmap so we can be consistent about where we want it. -r so we undo them in reverse order that they were formed
for dm in ls -1r /dev/mapper | grep -v control
; do echo “Unmapping $dm” ; cryptsetup luksClose /dev/mapper/$dm ; done
2h6. Decrypt the drive
echo “$PASS” | cryptsetup luksOpen $DEV crypt ### make sure undecrypted first
2h7. Inform LVM about our new volume
vgchange -ay reformvg
- Install new system on it
X reform-migrate /dev/reformvg/root
- Inform the system to activate the new volume group
X vgchange -an reformvg
- We are done with this here so un-decrypt it
X cryptsetup luksClose crypt
For now we’re going to retry the above.
202209212006MST - 2H57M
SO what we’ll do is save this first, then copy it to a text file, then run a script to process out what we want.
202209212123MST
Well I think if we use ‘sgdisk’ we can get rid of some of the “click here” stuff and go CLI all the way
So we’ll go up top and get rid of gnome-disk for formatting and use ‘sgdisk -o’ for a new GPT (GUID Partition Table)
–goes
202209212143NST
‘sgdisk’ has replaced ‘gnome-disks’. Now we try the test script.
202209221008MST copied the script to up top.
What does this do?
egrep - only take the commands run as root, starting with ‘>’ (quoted string), ‘#’ (root command), ’ ’ (space), and [[:alpha:]] (A-Z and a-z)
read line - process them line by line
read - show the user the line to run. If they hit [Enter], ‘Y’, or ‘y’ run it
202209220038
This has been iterated. Only one thing remains up top and that’s removing the extraneous ‘swap’ entries in ‘/etc/fstab’ at Step 2h4.
Now let’s take a look at actually installing the system. Mauro says to run ‘/usr/sbin/reform-migrate’ and that’s a short 107-line script filled with comments and ‘echo’. It also has many options but here we’re looking at a simple one. One hard drive partition, one crypto partition, one VG, two LVs, and there you go.
Here’s what it does:
echo "cryptsetup luksOpen /dev/nvme0n1 reform_crypt"
echo "vgchange -ay reformvg"
echo "reform-migrate /dev/reformvg/root"
echo "vgchange -an reformvg"
echo "cryptsetup luksClose reform_crypt"
vgchange -an reformvg
cryptsetup luksClose reform_crypt
echo “You can now reboot into your encrypted System.”
- In step 5 we un-decrypted ‘crypt’, so let’s redo that.
6a. Decrypt it
echo $PASS | cryptsetup luksOpen $DEV crypt
6b. Make sure the Volume Group is happy knowing about it being here
vgchange -ay reformvg
- Let’s see what reform-migrate brings us:
Usage would be reform-migrate --emmc /dev/mapper/root
7a. We’d have to map it first with luksOpen ### doesn’t seem to need this. Instead we’ll ‘partprobe’ to avoid stale filesystem info
partprobe
echo cryptsetup luksOpen /dev/mapper/reformvg-root ### is this needed or not?
7b. Create temporary mountpoint and mount it
MNT=/mnt/$USER/root ; if [ ! -d $MNT ]; then mkdir -p $MNT ; fi ; mount /dev/mapper/reformvg-root $MNT; echo “$DEV Mounted at: ls -l $MNT
” ; df | grep $MNT
7c1. Copy the new system from the sdcard to the USB/SDD/NvME. Note we ignore the “Do you really want to do this” since… we’ve wiped this disk twice now. No harm left!
rsync -axHAWXSv --exclude=timeshift/snapshots/* --numeric-ids --info=progress2 / $MNT
Notes:
timeshift - I installed timeshift and took a snapshot on the sdcard of the entire sdcard os
-a = -rlptqgoD no -HAX
r=recursive, l=keep symlinks as symlnks, p=preserve permissions, t=preserve mod times, q=quiet, g=preserve group, o=preserve owner, and D=preserve special files
-x = stay on one filesystem – makes no sense on a new initial sync
-H = preserve hard links
-A = preserve ACLs
-W =copy whole files without deltas - makes no sense on an initial rsync since it has to copy whole files
-X = preserve extended attributes
-S = make series of nulls into sparse blocks
-v = give us status on individual files… more useful than --progress
7c2. We’re done so unmount and unmap…
umount $MNT ; for dm in ls -1r /dev/mapper | grep -v control
; do echo “Unmapping $dm” ; cryptsetup luksClose /dev/mapper/$dm ; done
- This has been iterated enough times to make it clear this script works from scratch. The script is now up top.
X copy all this stuff here (^A ^C)
X cat > the_text_file [Enter] ^D
X echo ‘#!/bin/bash -xv’ > script.sh && chmod o+x script.sh
X egrep "^> # " the_text_file | sed -e ‘s/^> # //g’ >> script.sh && echo “Run ./script.sh to install.”
X ./script.sh
9+ Other instructions to make the hardware dip switch flip, and update the bootloader selection process.
Well get to that later.
202209220109MST
We’ve iterated through all Steps 1-7c1 and it works over and over and over. “Tomorrow” (later today)
we’ll tackle Steps 7a and whether we need a luksOpen there, and then deal with the hardware stuff.
202209220131
Finished the notes 1-3, the TODOs, did the rsync twice to see that it really worked and other than a couple
of ‘/var/log’ things and my own ‘.bash_history’ nothing got copied. Win.
202209220941MST
I’ve decided there’s no easy way to algorithmically ‘know’ with determenism which is our target device,
so let’s have the user input it.
202209221022MST
Break time. DEV stuff is fixed. Now working on other gotchas from running this multiple times.
202209221330MST
Back to it. Add ‘X’ for disabled commands. Retry script
- select all text here, ^C for copy
- in CLI cat > the_text_file
- shift-^V for paste
- ^D for end of file
- run the script
cat test.sh
#!/bin/bash
egrep “^> # [[:alpha:]]” the_text_file | sed -e “s/^> # //g”
./test.sh
Copy all the output and paste it back in a root shell. Answer two questions:
- Target device: (I used /dev/sda1)
- Encryption passphrase
Later we change this passphrase to the real one… hopefully longer and better than test ones:
cryptsetup luksChangeKey /dev/sdX
Example: sudo cryptsetup luksChangeKey /dev/sda1
(You could add multiple keys but we are kind of assuming you chose a short easy key for the install. Now time to ditch it. Also we could put this as a last step in the script, but what if YOU chose a GREAT passphrase… why force a change, and I hate asking questions in a script…)
202209221420MST
Got the mounts/umounts fixed. No issues. If you put it as a script you can specify $1 as the target device.
1 iteration tested
2nd iteration – now a script to build the script from this explanation
- copy all this stuff here (^A ^C)
- cat > the_text_file [Enter] ^D
- echo ‘#!/bin/bash -xv’ > script.sh && chmod o+x script.sh
- egrep "^> # " the_text_file | sed -e ‘s/^> # //g’ >> script.sh && echo “Run ./script.sh to install.”
- ./script.sh
2022091221413
3rd iteration done, let’s just let it go for the whole thing as per the 5 steps in 2nd iteration
202209221429
4th iteration done, fix a typo
5th iteration done, fix sed with ’ instead of escaping the ‘#’ in the substitution
6th iteration done, fix copy of script to just be a copy with ‘X’ in front… don’t run it then!
7th iteration done, no changes
8th iteration done, all good so remove temporary -n from rsync (don’t do it, just pretend, goes faster for debugging!)
9th iteration done, real rsync takes a while… sdcard read IOps are not high… this is not a secret. 8.5 Minutes averaged 16MB/sec
10th iteration done, and we fixed the /etc/fstab multiple swap entries, and preserve the old ones as comments and old file as ‘/etc/fstab.old’
11th iteration done, time sync ./script.sh still says 8.5 minutes
We’ll get on with the rest of the program shortly, but
MOUNTING:
- mount the encrypted PV cryptsetup luksOpen /dev/sda1 crypt
- mount the VG vgchange -ay
- create a mountpoint MNT=/mnt/root ; if [ ! -d $MNT ]; then mkdir -p $MNT ; fi ; mount /dev/reformvg/root $MNT
- enjoy. When done umount $MNT ; rmdir $MNT ; cryptsetup luksClose /dev/sda1 or reboot
202209221710MST I said I’d get to the rest of it today but thus far I’ve only perfected the software piece.
Started: Who knows with what.
Ended: This “Explanation” and the script generate a 31 line script that only needs two inputs: Target Device, and Encryption Phrase, and it does the rest.
Next up:
- Configuring booting from NVMe. Mauro refers readers to the Operators Handbook but we’ll cut it short here. Screwdriver needed to remove heatsink and flip DIP switch. (Well also to install NVMe).
- Will have to get this file HYPERTEXT://mntreDOTCOM/reform_md/flash-rescue-reform-init.bin
- Unlock boot partition echo 0 > /sys/class/block/mmcblk0boot0/force_ro
- Flash the binary dd if=flash-rescue-reform-init.bin of=/dev/mmcblk0boot0 bs=1024 seek=33
-Configure reform-init ###look at that### to use nvme because the name matters###
reform-boot-config nvme
20220922MST we’ll flesh all that out after I enjoy this top-round roast, thinly shaved over brioche bun with au jus for dipping.
202209231934MST
Almost a day has gone by. Let’s see what we need to do here… First, we’re done with Mauro’s info so let’s go to the next step with
the Operator’s Handbook and Bibliocar with kudos to Mtnmn at HYPERTEXTs://community.mnt.re/t/how-do-i-create-a-bootable-image/533/4
- We want to get that boot image.
cd /usr/local/bin &&& wget HYPERTEXT://mntreDOTCOM/reform_md/flash-rescue-reform-init.bin
- Allow the boot partition to be writeable (normally read-only)
echo 0 > /sys/class/block/mmcblk0boot0/force_ro
- Flash that binary
dd if=flash-rescue-reform-init.bin of=/dev/mmcblk0boot0 bs=1024 seek=33 ### how do we know to mess with /dev/mmcblok0boot0?
- Configure reform-init, and here’s where some of what Bibliocar said Mtnmn said will come in handy ###
The last Mauro suggestion was reform-boot-config nvme and he said nvme was important because the name
matters, and Bibliocar pretty much said it had to have “usb” or “nvme” or be “/dev/sdaX”. Let’s dig in.
‘/usr/sbin/reform-boot-config’ is 132 lines (at present) and a lot is very talkative. Let’s distill it down.
-
have to run it as ‘root’
-
the usage is ‘reform-boot-config [-emmc] {sd,nmve,usb,emmc}’
the -emmc means we are serious about emmc and also have to flip the DIP switch under the heatsink
-
from the script, the selection of the parameter gets us:
Choosing sd, nvme, usb or emmc will set the root partition to /dev/mmcblk1p2, /dev/nvme0n1p1, /dev/sda1 or /dev/mmcblk0p2,
respectively.i" <— (why is this ‘i’ there??? -ed)
“You can choose another root partition by passing the absolute device path starting with /dev/ explicitly,
For example, to boot from an LVM volume, run: reform-boot-config /dev/reformvg/root”
-
Well that’s awfully convenient for us. We know it’s going to be the LVM volume thing… and it won’t require a DIP switch flip,
so effectively we’ll puzzle out what ‘reform-boot-config /dev/reformvg/root’ will do.
-
if ‘/mnt’ has something mounted there the whole damn script aborts. Seriously? Go use ‘mktemp’. Sigh.
-
it then sets ‘$ROOTPART’ based on the choice to either ‘mmcblk1p2’, ‘nvme0n1p1’, ‘sda1’, ‘mmcblk0p2’ respectively.
-
if there is no such block device as ‘/dev/$ROOTPART’ quit again… unlike my script that just prompts you again.
-
defines cleanup() to umount /mnt/boot, /mnt/dev, /mnt/sys, /mnt/proc and /mnt
-
sets that as the trap for EXIT INT TERM
-
mounts /mnt (/dev/sda1), /mnt/boot (our existing /boot which is /dev/mmc1blk1p1) and special mount (bind) /mnt/dev and mounts /dev/sysfs and /dev/proc
-
verifies ‘/mnt/etc/fstab’ is right, and adds /mnt and mnt/boot to it
-
it then updates the inital ramdisk filesystem (‘update-initramfs’)
-
it then either tells you your boot partition is on nvme and flip the switch to off, or it’s on the sdcard and flip the switch off. THIS IS WRONG because if it’s on USB it will still tell you it’s on sdcard.
-
reboot.
OK, what about reform-init? It starts off like this:
Read config file generated by reform-boot-config script
BOOTPREF=$(cat /reform-boot-medium)
Default to SD card
BOOTPART=“/dev/mmcblk1p1”
But reform-boot-config ISN’T created by reform-boot-config and DOESN’T EXIST anywhere on the system!
The rest of this is just poor coding. Try this, then that, and never look up the real settings and repetitive code.
This will need to be rewritten. Not on a Friday Night, says I.
This IS EXACTLY what Biblio did. So now I know this is the right way to go. I just have to think of an elegant
way to do this. Also I’m thinking “If the way you’re told to do this failed, just go back to the SDcard”. That way
we kind of have a safe mode. The problem there is how to prevent a loop. Will sleep on that. ###
202209232006MST