Showing posts with label snippets. Show all posts
Showing posts with label snippets. Show all posts

Friday, August 29, 2025

MacOS VM hints

Useful obscure projects for MacOS virtualization: 

  • UTM (https://mac.getutm.app/)
  • QuickEmu (https://github.com/quickemu-project)
  • Tart (https://tart.run/) 

Nothing works perfectly, except (I've heard) Parallels, which I haven't yet tried.

VMWare fusion sucks. Virtualbox sucks more.

UTM is quite nice. QuickEmu and Tart lack a GUI.

Tart supplies images with xcode preinstalled, so you won't need to use the app store. 

Tips from QuickEmu (haven't tried them in others):

 sudo trimforce enable

Enables SSD TRIM commands on the guest, helping qemu to shrink the QCOW image. Comes complete with a scary screenful of warnings that can be safely ignored, we're in a VM dude. Might not always work, google it.

MacOS VMs will usually be blocked from logging in with Apple IDs by default, due to the Serial, MAC Address, and other information being shared between multiple VMs.

To fix this, you can use this tool to replace or randomize these values in the bootloader.

 https://github.com/quickemu-project/qe_mac_apid

If you see "Your device or computer could not be verified" when you try to login to the App Store, make sure that your wired ethernet device is en0. Use ifconfig in a terminal to verify this.

If the wired ethernet device is not en0, then then go to System Preferences -> Network, delete all the network devices and apply the changes. Next, open a terminal and run the following:

sudo rm /Library/Preferences/SystemConfiguration/NetworkInterfaces.plist

Now reboot, and the App Store should work.

Tips from UTM: 

How to resize MacOS VM image (from https://github.com/utmapp/UTM/issues/4186#issuecomment-2163220345):

If you want to be able to increase the size of your disk image while retaining the ability to upgrade your OS, the Apple_APFS_Recovery partition must be relocated to the end of the disk before expanding the main Apple_APFS container.

So far the only ready-made solution I have found is the Tart packer plugin from the Tart project by cirruslabs which allows for automated VM creation and has the option to automatically resize disk images (see the recovery_partition = "relocate" option).

More information on the projects can be found below:
https://github.com/cirruslabs/tart
https://github.com/cirruslabs/packer-plugin-tart/tree/main

Since I wanted to continue using UTM and simply needed a standalone tool to relocate the partition, I created a small tool based on their code. Understand that it come with no guarantee, but the code is available here:
https://gist.github.com/cdavidc/3509ceefba518f20d1c123b6435407d6

(fully copied below because these things tend to get lost)

// Code taken from https://github.com/cirruslabs/packer-plugin-tart/blob/main/builder/tart/recoverypartition/relocate.go
// to create a standalone tool to relocate Apple_APFS_Recovery partitions to the end of a macOS disk image
// Build with:
// 	go mod init RelocatePartition.go
// 	go mod tidy
// 	go build RelocatePartition.go
// Run with:
// 	./RelocatePartition path_to_disk_image

package main

import (
	"fmt"
	"github.com/diskfs/go-diskfs"
	"github.com/diskfs/go-diskfs/partition/gpt"
	"github.com/samber/lo"
	"io"
	"os"
)

const Name = "RecoveryOSContainer"

func Relocate(diskImagePath string) error {
	// Open the disk image and read its partition table
	disk, err := diskfs.Open(diskImagePath)
	if err != nil {
		return fmt.Errorf("failed to open the disk image: %w", err)
	}

	partitionTable, err := disk.GetPartitionTable()
	if err != nil {
		return fmt.Errorf("failed to get the partition table: %w", err)
	}

	// We only support relocating a recovery partition on a GPT table
	gptTable, ok := partitionTable.(*gpt.Table)
	if !ok {
		return fmt.Errorf("expected a \"gpt\" partition table, got %q", partitionTable.Type())
	}

	// Find the recovery partition
	recoveryPartition, recoveryPartitionIndex, ok := lo.FindIndexOf(gptTable.Partitions, func(partition *gpt.Partition) bool {
		return partition.Name == Name
	})
	if !ok {
		fmt.Println("Nothing to relocate: no recovery partition found.")

		return nil
	}

	// We only support relocating the recovery partition if it's the last partition on disk
	if (recoveryPartitionIndex + 1) != len(gptTable.Partitions) {
		return fmt.Errorf("cannot relocate the recovery partition since it's not the last partition " +
			"on disk")
	}

	// Determine the last sector available for partitions, which is normally the (total LBA - 34) sector[1]
	//
	// [1]: https://commons.wikimedia.org/wiki/File:GUID_Partition_Table_Scheme.svg
	lastSectorAvailableForPartitions := uint64((disk.Size / disk.LogicalBlocksize) - 34)

	// Perhaps the recovery partition already resides at the last sector available for partitions?
	if recoveryPartition.End >= lastSectorAvailableForPartitions {
		fmt.Println("Nothing to relocate: recovery partition already ends at the last sector available to partitions.")

		return nil
	}

	fmt.Println("Dumping recovery partition contents...")

	tmpFile, err := os.CreateTemp("", "")
	if err != nil {
		return fmt.Errorf("failed to create a temporary file for storing "+
			"the recovery partition contents: %w", err)
	}
	defer os.Remove(tmpFile.Name())

	if err := dumpPartition(diskImagePath, tmpFile.Name(), recoveryPartition.GetStart(), recoveryPartition.GetSize()); err != nil {
		return fmt.Errorf("failed to dump the recovery partition contents: %w", err)
	}

	fmt.Println("Re-partitioning the disk to adjust the recovery partition bounds...")

	recoveryPartitionSizeInSectors := recoveryPartition.End - recoveryPartition.Start

	recoveryPartition.Start = lastSectorAvailableForPartitions - recoveryPartitionSizeInSectors
	recoveryPartition.End = lastSectorAvailableForPartitions

	// Re-partition the disk with the new recovery partition bounds
	if err := disk.Partition(gptTable); err != nil {
		return fmt.Errorf("failed to write the new partition table: %w", err)
	}

	fmt.Println("Restoring recovery partition contents...")

	if err := restorePartition(diskImagePath, tmpFile.Name(), recoveryPartition.GetStart(), recoveryPartition.GetSize()); err != nil {
		return fmt.Errorf("failed to restore the recovery partition contents: %w", err)
	}

	return nil
}

func dumpPartition(diskFilePath string, partitionFilePath string, off int64, n int64) error {
	diskFile, err := os.Open(diskFilePath)
	if err != nil {
		return err
	}
	defer diskFile.Close()

	partitionFile, err := os.Create(partitionFilePath)
	if err != nil {
		return err
	}

	partitionContentsReader := io.NewSectionReader(diskFile, off, n)

	if _, err := io.Copy(partitionFile, partitionContentsReader); err != nil {
		return err
	}

	return nil
}

func restorePartition(diskFilePath string, partitionFilePath string, off int64, n int64) error {
	diskFile, err := os.OpenFile(diskFilePath, os.O_RDWR, 0600)
	if err != nil {
		return err
	}

	contentsFile, err := os.Open(partitionFilePath)
	if err != nil {
		return err
	}
	defer contentsFile.Close()

	partitionContentsWriter := io.NewOffsetWriter(diskFile, off)

	if _, err := io.CopyN(partitionContentsWriter, contentsFile, n); err != nil {
		return err
	}

	return diskFile.Close()
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage:", os.Args[0], "path_to_disk_image")
		os.Exit(1)
	}
	diskImageFilePath := os.Args[1]
	Relocate(diskImageFilePath)
}

 

To build it, install go (with brew for instance) and execute the few commands listed in the comments at the beginning of the file.

Considering that, the full instructions are:

  1. Locate the VM image in UTM by right-clicking on the VM and select "Show in Finder"
  2. Resize the image using hdiutil resize -size <new_size_in_GB>g -imageonly -verbose <full_path_and_name_of_the_image_file>
  3. cd to where you built the RelocatePartition tool and run ./RelocatePartition <full_path_and_name_of_the_image_file>
  4. Close and re-open UTM, so it re-reads the VM config, then start the VM in the recovery mode
  5. Use diskutil list to get the list of the containers (the first block in the output) and located the Apple_APFS container
  6. Resize the APFS container with diskutil apfs resizeContainer <id_of_the_Apple_APFS_container> 0
  7. Restart the VM

I also disable SIP (boot into recovery, there's an option in UTM to do that by right-clicking on the VM, open a terminal, csrutil disable) then remove all apple bundled bullshit (books, tv, etc), then re-enable SIP.

Conversion between raw image and qcow2: https://github.com/utmapp/UTM/discussions/3784 

 

 

  

 

 

 

 

Sunday, March 18, 2018

[snippets] grep

grep -v -F -f aggouria -x salata > piato

Afairei ta aggouria apo th salata kai ta vazei sto piato.

Wednesday, February 01, 2017

[snippets]: Virtualbox headless VM creation

5  VBoxManage list ostypes
6  VBoxManage createvm --name "Windows 7" --ostype Windows7_64 --register
14  cd VirtualBox\ VMs/
16  cd Windows\ 7/
18  VBoxManage createhd --filename "Windows7.vdi" --size 10000
28  VBoxManage modifyvm "Windows 7" --memory 1024 --acpi on --boot1 
    dvd --nic1 nat
32  vboxmanage storagectl "Windows 7" --name "SATA" --add sata 
    --controller IntelAHCI
35  vboxmanage storageattach "Windows 7" --storagectl "SATA" --port 0 
    --device 0 --type hdd --medium "Windows7.vdi"
36  vboxmanage storageattach "Windows 7" --storagectl "SATA" --port 1 
    --device 0 --type dvddrive --medium /home/blabla/Windows7.iso
48  vboxmanage modifyvm "Windows 7" --vrde on
49  vboxheadless --startvm "Windows 7"
57  vboxmanage modifyvm "Windows 7" --nic1 bridged
61  vboxmanage modifyvm "Windows 7" --bridgeadapter1 enp2s0f1



then connect with RDP to port 3389 

Saturday, July 04, 2015

[snippets] Migrate IMAP mailboxes from Dovecot A to Dovecot B

Logged in on B:

$ doveadm -D -v -o imapc_features="rfc822.size fetch-headers" -o mail_prefetch_count=20 -o imapc_user=ricudis -o imapc_password=topoulimoueinai38ekatosta -o imapc_host=dovecot-a.net -o imapc_port=993 -o imapc_ssl=imaps -o imapc_ssl_verify=no backup -R -u ricudis@dovecot-a.net imapc:

(modify for no SSL as appropriate, etc) 

Saturday, June 13, 2015

Tuesday, May 19, 2015

[snippets]: HP DL380 Gen9 "Smart" Storage Array Setup Howto In 29 Easy Steps


  1. Power on the server
  2. Wait 2 to 3 weeks until POST system checks complete and system complains about uninitialized SSA array. 
  3. Go through a maze of menus, all alike, until you finally find the well hidden embedded Smart Storage Administration tool. 
  4. Boot into the SSA tool. 
  5. Wait hopelessly as a counter counts to infinity while "trying to collect system configuration information". 
  6. Read the SSA manuals and release notes
  7. Find no relevant information
  8. Google for the SSA error messages on the counter-to-infinity screen. 
  9. Find nothing. 
  10. Google for the offline version of the SSA tool, download ISO, burn it to CD. 
  11. Reboot the server
  12. Wait another 2 to 3 weeks until POST system checks complete
  13. Bypass complaints about uninitialized SSA array. 
  14. Try to boot from the CD. 
  15. Fail because the CD doesn't support EFI boot. 
  16. Switch to BIOS boot method
  17. Step 15 requires a reboot. Wait 2 to 3 weeks more. 
  18. Boot from the CD into the offline version of SSA. 
  19. Google again for a newer version of SSA because the one you downloaded is 15 years old. 
  20. Burn newer version to CD. 
  21. Reboot using the updated version of SSA. Wait 2 to 3 weeks. 
  22. This one "works", in contrast with the embedded one. 
  23. Get a full array report to check drive status for any errors. 
  24. Pay attention to the naming of controller flag entries in the report output. There are "Controller Flags", "Extended Controller Flags", "More Controller Flags" and "Even More Controller Flags". 
  25. Configure the array, assign physical drives, and select the "rapid" initialization mode. 
  26. While waiting for the "rapid" initialization mode to complete, make children, grow them up, ensure they go to university. 
  27. Around the time of their post-graduation ceremony, "rapid" initialization of array is finished. 
  28. Did I tell you that array is not available to the OS before "rapid" initialization mode completes? 
  29. To Be Continued.

Saturday, May 02, 2015