Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

joevt

Contributor
Jun 21, 2012
6,660
4,078
yes, I want to combine the user interaction to one window per OS.

I would like to have a scrollable dialog in AppleScript, but this is not available without extensions. In case you know a failsave method what is compatible for all the OS versions I would like to add it. Somewhere I limited display to x lines for dialog text, need to check that again.

Also I did not find a method to check if sudo is still cached. As each do shell script command in AppleScript has its own ID I can not detect if the next command uses the cached password.

Maybe just make a boolean if the dialog was presented the first time. I do want to explain why the user has to give an admin password, of course.
I think one sudo script to gather all the info. Then you can have one sudo script to fix problems. Or one sudo per OS if you really want to split them up. Or give the user a choice - fix all or fix one at a time.

Regarding the UI: Maybe see how OCLP uses python for its UI? I think it uses wxPython? That project might be a little large for this simple mount, compare, and fix task.

There's a scrollable list for AppleScript:
https://www.macscripter.net/t/how-to-create-a-display-dialog-with-scrollbars/71688/4

Here's a dialog with scrollable text (click the "★Click Here to Open This Script" button):
http://piyocast.com/as/archives/6695
 
  • Like
Reactions: Macschrauber

joevt

Contributor
Jun 21, 2012
6,660
4,078
I did another bleeding edge pre-version.
Tried it in High Sierra (with partitions that have been previously fixed):
- The progress bar has "mounting:" with no names for some partitions. If it can't get a name, then maybe it should show device id like disk10s5? Or it should show device id anyway in case multiple volumes have the same name.
- The progress bar says plists match for BigSur Data's Preboot even though it can't mount the System volume?
- I think it's confused about Catalina. It says "Catalina Data's Preboot is: [10.15.7] Can not compare (System Volume not mounted)"
- The dialog automatically closes after a few minutes. I don't think it should close unless I click the OK button.
- The app unmounts Preboot volumes even if it wasn't responsible for mounting them. Before mounting, check if already mounted. If not then mount, and add it to a list of volumes to unmount.

The Preboot for Catalina is supposed to use System volume UUID. If there's a UUID folder referring to the Data volume then it should be removed if it doesn't contain /System/Library/CoreServices/boot.efi and the SystemVersion.plist has 10.15.7 or less.
For Big Sur and later, each Preboot has a Data UUID folder.
A volume group UUID is the same as the UUID that is used for Preboot.

I removed the Catalina Data volume UUID and took a final screenshot.

For High Sierra:
It knows about System role but not Data role or Volume group. diskutil knows which disk is System role but can't get UUID of System volume for BigSur and later which is probably one reason why Apple switched Preboot volume to use Data UUID folder instead of System UUID folder for Big Sur and later.

Tried it in Sonoma after reboot from High Sierra messed up the partitions.
- The app doesn't repair .contentDetails or .disk_labels.
- I clicked Fix and show files for Catalina Data. There was one click per file. I guess High Sierra recreated the Data volume UUID from Preboot.
- Surprisingly, High Sierra did not mess up other Preboot partitions. Because of modification dates? I don't know.
- I ran it again to show that Catalina Data was fixed. It shows Catalina twice. I guess one is for the correct System volume UUID and the other is for the Data volume UUID. I don't know why High Sierra doesn't add a data volume UUID folder for CatalinaE.

Rebooted into High Sierra and went back to Sonoma and then tried "Fix" instead of "Fix and Show Files"
- Volumes appear in different order (probably device order?). Maybe they should be sorted by name before being processed for consistancy in the screenshots.
 

Attachments

  • Preboot fixer 10-1 joevt.zip
    7.6 MB · Views: 25
  • Like
Reactions: Macschrauber

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
Tried it in High Sierra (with partitions that have been previously fixed):
- The progress bar has "mounting:" with no names for some partitions. If it can't get a name, then maybe it should show device id like disk10s5? Or it should show device id anyway in case multiple volumes have the same name.
- The progress bar says plists match for BigSur Data's Preboot even though it can't mount the System volume?
- I think it's confused about Catalina. It says "Catalina Data's Preboot is: [10.15.7] Can not compare (System Volume not mounted)"
- The dialog automatically closes after a few minutes. I don't think it should close unless I click the OK button.
- The app unmounts Preboot volumes even if it wasn't responsible for mounting them. Before mounting, check if already mounted. If not then mount, and add it to a list of volumes to unmount.

The Preboot for Catalina is supposed to use System volume UUID. If there's a UUID folder referring to the Data volume then it should be removed if it doesn't contain /System/Library/CoreServices/boot.efi and the SystemVersion.plist has 10.15.7 or less.
For Big Sur and later, each Preboot has a Data UUID folder.
A volume group UUID is the same as the UUID that is used for Preboot.

I removed the Catalina Data volume UUID and took a final screenshot.

For High Sierra:
It knows about System role but not Data role or Volume group. diskutil knows which disk is System role but can't get UUID of System volume for BigSur and later which is probably one reason why Apple switched Preboot volume to use Data UUID folder instead of System UUID folder for Big Sur and later.

Tried it in Sonoma after reboot from High Sierra messed up the partitions.
- The app doesn't repair .contentDetails or .disk_labels.
- I clicked Fix and show files for Catalina Data. There was one click per file. I guess High Sierra recreated the Data volume UUID from Preboot.
- Surprisingly, High Sierra did not mess up other Preboot partitions. Because of modification dates? I don't know.
- I ran it again to show that Catalina Data was fixed. It shows Catalina twice. I guess one is for the correct System volume UUID and the other is for the Data volume UUID. I don't know why High Sierra doesn't add a data volume UUID folder for CatalinaE.

Rebooted into High Sierra and went back to Sonoma and then tried "Fix" instead of "Fix and Show Files"
- Volumes appear in different order (probably device order?). Maybe they should be sorted by name before being processed for consistancy in the screenshots.


A deep thank you for your detailed testings.

At the moment I am struggling with the Catalina APFS variant:
As you noticed, on Catalina the Preboot Volume has the UUID of the Catalina System volume like the earlier APFS1 OS (late Sierra to Mojave).

But we found a Preboot folder with the UUID of the Catalina Data volume, partially filled, no boot.efi in Coreservices and files from 2018ish (Catalina came 2019)

So we just delete it as this seems to be messed up by High Sierra ?!

Now I just ignore Preboots if they do not contain a boot.efi file in CoreServices. I am a bit shy to delete Preboots...

Thats the reason why Catalina is listed twice, the logic is doubled for Catalina, as there the Data Volume and the System Volume has it's UUID present in the Catalina Preboot. As said APFS1 is System (of course, just one volume) and Big Sur & later it's the UUID of the Data volume.


---

I noticed also, after modifying the date of SystemVersion.plist and Platformsupport.plist that I could not make High Sierra messing in other Preboots again. This needs more testing of course, but sounds promising.

---

I made a list of what's mounted before and unmount just what I mount.

---

There's a glitch with unmounting the other System volumes. If we unmount the System volume with diskutil unmount diskxsy the Data volume disappears in the Finder and the sidebar. Tho it is not unmounted and accessible thru the file system like the Terminal or by go-to-folder: /Volumes/

So I do not unmount the other System volumes, that would scare the user to death, disappearing in the Finder :]

---

The report dialog at the end of the script just closes for setting it into login items. So it would not disturb too much.


no bleeding edge version today, needs more testing...
 

joevt

Contributor
Jun 21, 2012
6,660
4,078
A deep thank you for your detailed testings.

At the moment I am struggling with the Catalina APFS variant:
As you noticed, on Catalina the Preboot Volume has the UUID of the Catalina System volume like the earlier APFS1 OS (late Sierra to Mojave).

But we found a Preboot folder with the UUID of the Catalina Data volume, partially filled, no boot.efi in Coreservices and files from 2018ish (Catalina came 2019)

So we just delete it as this seems to be messed up by High Sierra ?!

Now I just ignore Preboots if they do not contain a boot.efi file in CoreServices. I am a bit shy to delete Preboots...

Thats the reason why Catalina is listed twice, the logic is doubled for Catalina, as there the Data Volume and the System Volume has it's UUID present in the Catalina Preboot. As said APFS1 is System (of course, just one volume) and Big Sur & later it's the UUID of the Data volume.
Maybe you want to check the list of files to make sure it doesn't contain anything interesting? Ignore .DS_Store, .disk_label*, and the files that we know High Sierra adds. If the remaining files is not empty then just tell the user something fishy is there - a UUID folder that doesn't have a boot.efi file. Otherwise it can be safely removed.

Code:
{ shopt -s nullglob || setopt NULL_GLOB } 2> /dev/null
for thepreboot in \
	/Volumes/Preboot*/????????-????-????-????-???????????? \
	/System/Volumes/Preboot/????????-????-????-????-???????????? \
; do
	if ((
		$(
			find "$thepreboot" -type f \
				-name 'boot.efi' \
			| wc -l
		)
	)); then
		echo 'found boot.efi in "'"$thepreboot"'"'
	elif ((
		$(
			find "$thepreboot" -type f \
				-not -name .root_uuid \
				-not -name '.DS_Store' \
				-not -name '.disk_label*' \
				-not -name .contentDetails \
				-not -name boot.efi.j680ap.im4m \
				-not -name boot.efi.j132ap.im4m \
				-not -name boot.efi.j137ap.im4m \
				-not -name com.apple.Boot.plist \
				-not -name PlatformSupport.plist \
				-not -name SystemVersion.plist \
			| wc -l
		)
	)); then
		echo 'maybe delete fishy "'"$thepreboot"'"'
	else
		echo 'ok to delete "'"$thepreboot"'"'
	fi
done
 
  • Like
Reactions: Macschrauber

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
I found a Catalina HD I did not touched for a long time:

Code:
/dev/disk5 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +1000.0 GB  disk5
                                 Physical Store disk4s2
   1:                APFS Volume ⁨1000 - Daten⁩            10.1 GB    disk5s1
   2:                APFS Volume ⁨Preboot⁩                 36.0 MB    disk5s2
   3:                APFS Volume ⁨Recovery⁩                525.8 MB   disk5s3
   4:                APFS Volume ⁨Catalina SSHD⁩           11.3 GB    disk5s4
   5:                APFS Volume ⁨VM⁩                      1.1 GB     disk5s5

mac@Mac-Pro ~ % diskutil mount disk5s2
Volume Preboot on disk5s2 mounted

mac@Mac-Pro ~ % cd /Volumes/Preboot 
mac@Mac-Pro Preboot % ls
3B6602A8-5861-44B1-A699-4FF94194546D	A3B9381B-A6D7-48FC-AEF3-B40C6023C0EE
mac@Mac-Pro Preboot % diskutil info 3B6602A8-5861-44B1-A699-4FF94194546D
   Device Identifier:         disk5s1
   Device Node:               /dev/disk5s1
   Whole:                     No
   Part of Whole:             disk5

   Volume Name:               1000 - Daten
   Mounted:                   Yes
   Mount Point:               /Volumes/1000 - Daten

   Partition Type:            41504653-0000-11AA-AA11-00306543ECAC
   File System Personality:   APFS
   Type (Bundle):             apfs
   Name (User Visible):       APFS
   Owners:                    Enabled

   OS Can Be Installed:       Yes
   Booter Disk:               disk5s2
   Recovery Disk:             disk5s3
   Media Type:                Generic
   Protocol:                  SATA
   SMART Status:              Verified
   Volume UUID:               3B6602A8-5861-44B1-A699-4FF94194546D
   Disk / Partition UUID:     3B6602A8-5861-44B1-A699-4FF94194546D

   Disk Size:                 1000.0 GB (999995129856 Bytes) (exactly 1953115488 512-Byte-Units)
   Device Block Size:         4096 Bytes

   Container Total Space:     1000.0 GB (999995129856 Bytes) (exactly 1953115488 512-Byte-Units)
   Container Free Space:      976.8 GB (976766828544 Bytes) (exactly 1907747712 512-Byte-Units)
   Allocation Block Size:     4096 Bytes

   Media OS Use Only:         No
   Media Read-Only:           No
   Volume Read-Only:          No

   Device Location:           Internal
   Removable Media:           Fixed

   Solid State:               No
   Hardware AES Support:      No
   Device Location:           "Bay 2"

   This disk is an APFS Volume.  APFS Information:
   APFS Container:            disk5
   APFS Physical Store:       disk4s2
   Fusion Drive:              No
   APFS Volume Group:         3B6602A8-5861-44B1-A699-4FF94194546D
   Encrypted:                 No
   FileVault:                 No
   Sealed:                    No
   Locked:                    No

mac@Mac-Pro Preboot % cd 3B6602A8-5861-44B1-A699-4FF94194546D 
mac@Mac-Pro 3B6602A8-5861-44B1-A699-4FF94194546D % ls
Library	System	usr
mac@Mac-Pro 3B6602A8-5861-44B1-A699-4FF94194546D % cd System/Library/CoreServices 
mac@Mac-Pro CoreServices % ls
PlatformSupport.plist	SystemVersion.plist	boot.efi.j132ap.im4m	boot.efi.j137ap.im4m	boot.efi.j680ap.im4m
so this is exactly what High Sierra is writing.

I compared this "High Sierra written Catalina Data Preboot" folder with a High Sierra Preboot folder and the most of it matches, SystemVersion.plist differs in revision, maybe that old spinner missed an update.

Bildschirmfoto 2024-01-12 um 13.30.51.png


Also here is the "High Sierra written Catalina Data Preboot" against the correct "Catalina System Volume Preboot". We see in date and size that they differ - and in date that they are from High Sierra.
Bildschirmfoto 2024-01-12 um 13.39.08.png
 
Last edited:

joevt

Contributor
Jun 21, 2012
6,660
4,078
I wonder why my latest High Sierra created Catalina Data volume UUID preboot folder doesn't have the usr folder. I guess those should be in the list of files to ignore when checking if the preboot folder has files that should not be deleted.
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
I did some more changes:

Regarding the .disklabel files I could not directly compare them for all OS. Big Sur and later do not have those label files stored in CoreServices, but as .contentDetails is generated by High Sierra with " - data" in it (changes with the language), I simply checked for a text " - " in .contentDetails and present the disklabel editor dialog.

Also some guys, including me, gave the Preboots another name, changing them without interaction is not nice :)

As I wanted an initial dialog when running the script I set a selection to show the disk label editor for every OS or for OS' where a High Sierra manipulation was assumed.
Bildschirmfoto 2024-01-13 um 19.37.33.png



The Disk Label Editor:
Bildschirmfoto 2024-01-13 um 18.50.26.png

Bildschirmfoto 2024-01-13 um 18.50.34.png


A downside is: I use the disklabel file as Display Dialog icon, in dark mode this is black on dark grey, so barely visible. I would need a method do invert the icon.
Bildschirmfoto 2024-01-13 um 18.56.51.png




checking for Catalina - Data - Preboots - without boot.efi,
doing some additional checks, like if it's really a data volume or SystemVersion.plist is from High Sierra.
If all that matches the users gets a dialog to let him delete.
Bildschirmfoto 2024-01-13 um 19.59.24.png



so there's another bleeding edge version attached. Needs adjusting with
xattr -cr ~/Downloads/Preboot\ fixer\ 13-1.app
when a damaged dialog appears.
 
Last edited:

joevt

Contributor
Jun 21, 2012
6,660
4,078
Regarding the .disklabel files I could not directly compare them for all OS. Big Sur and later do not have those label files stored in CoreServices, but as .contentDetails is generated by High Sierra with " - data" in it (changes with the language), I simply checked for a text " - " in .contentDetails and present the disklabel editor dialog.

Also some guys, including me, gave the Preboots another name, changing them without interaction is not nice :)
I don't think any guys would prefer " - Data" (note the uppercase D) in there booter names.

As I wanted an initial dialog when running the script I set a selection to show the disk label editor for every OS or for OS' where a High Sierra manipulation was assumed.

The Disk Label Editor:

A downside is: I use the disklabel file as Display Dialog icon, in dark mode this is black on dark grey, so barely visible. I would need a method do invert the icon.
The disk label is a very simple format. No compression. 8 bits per pixel. You just need a method to map the 8 bit values into a pixel color.
The format is described at https://refit.sourceforge.net/info/vollabel.html

My convert_label command in DiskUtil.sh uses the tr -C command to convert every non-valid (non-grayscale) pixel value to white. The second tr command translates the Mac 8-bit CLUT values to grayscale values.
0x00 -> 0x00
0xf6 -> 0x11
...
0xd6 -> 0xff

I suppose the best way to treat the disk_label image is as an alpha mask that determines the ratio between a background color and a foreground color.
0x00 is 100% background color and 0% foreground color.
0x11 is 17/255 background color and 238/255 foreground color.
0xff is 0% background color and 100% foreground color.

light mode and dark mode will have different background colors. In light mode, the foreground color should probably be black. In dark mode, the foreground color should probably be white.

So you need two icons. One for light mode and one for dark mode. They both use the same alpha mask. The light mode icon will be solid black. The dark mode icon will be solid white. Maybe there's an icon type that allows defining a light mode and dark mode version but that might get complicated?

Are you drawing the .disk_label or .disk_label_2x? The latter should be used for retina mode. My iMac doesn't have a Retina display though.

checking for Catalina - Data - Preboots - without boot.efi,
doing some additional checks, like if it's really a data volume or SystemVersion.plist is from High Sierra.
If all that matches the users gets a dialog to let him delete.
View attachment 2336067


so there's another bleeding edge version attached. Needs adjusting with
xattr -cr ~/Downloads/Preboot\ fixer\ 13-1.app
when a damaged dialog appears.
  • The label editor scales the icon to fit the icon area. It's a little strange since Apple Startup Manager and Open Core Picker doesn't do that.
  • The label editor repeats until you click "Don't change" which I guess makes sense since it allows you to verify the change.
  • The label editor doesn't show the macOS version. This might be useful for determining a name for the booter.
  • You can enter a multiline disk label (press option and return for newline) but the utility puts the two lines together on the same line. See the BigSur11.7.2 screen shot (I meant to type 11.7.10). My makemultilinedisklabel command can create multiline disk labels.
  • If a file is missing, it shows [] instead of "missing".
  • The log file doesn't include label changes?
  • The log file uses newline between log entries. Multiline log entries split their lines with carriage return. Not really a problem. Console.app displays it fine. For BBEdit.app, the user will need to replace carriage returns with newlines.
 

Attachments

  • Preboot fixer disk label editor.zip
    1.5 MB · Views: 20
  • Like
Reactions: Macschrauber

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
The word for the data volume is set, I guess, by the installer. Depending on the language. Some of my OS run in German, some in English. So I see a mix. If the tool is guessing a changed label wrong, it just presents the editor, nothing gets changed before someone enters a new name.

I am pretty limited to what the AppleScript dialog can draw as an icon file.
It just accepts the disk_label format, the retina _2x format is not drawn.

Also I am limited how Display Dialog can read text inputs.

At the moment I use disklabel from the OpenCore package to convert text to disklabel. The drawing of the disklabel does AppleScript directly.


I will try your disklabel converter if its more flexible.

My plan is to invert the disklabel in dark mode, if I get this managed.
Edit: done, reversed the grey scale values in the .diskicon file before converting



Some fine tuning will follow, thanks for your suggestions.
 
Last edited:

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
it's a bit frustrating,
got it managed to invert the disk_label_2x, but no matter what I do with the shades of grey it is far away from a clear font in dark mode. 2nd picture is inverted.

Screenshot 2024-01-14 at 20.09.45.png

Screenshot 2024-01-14 at 20.11.45.png

Screenshot 2024-01-14 at 20.13.21.png
 

joevt

Contributor
Jun 21, 2012
6,660
4,078
it's a bit frustrating,
got it managed to invert the disk_label_2x, but no matter what I do with the shades of grey it is far away from a clear font in dark mode. 2nd picture is inverted.
What method do you use to invert and draw?

The problem with the inversion is that your text becomes the transparent color instead of a white color and the background becomes a black color instead of remaining as a transparent color.

If the transparent color is 0x00 and you want to invert 0xff, then you need to invert it to 0x01 instead of 0x00. All pixels that are 0x00 should remain as 0x00.
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
What method do you use to invert and draw?

The problem with the inversion is that your text becomes the transparent color instead of a white color and the background becomes a black color instead of remaining as a transparent color.

If the transparent color is 0x00 and you want to invert 0xff, then you need to invert it to 0x01 instead of 0x00. All pixels that are 0x00 should remain as 0x00.


I invert the original .disk_label_2x by byte swaps and convert that with OpenCore disklabel to .ppm by byte swapping the darkest black to the whitest white. Did the step to replace first to index bytes to adjust the grey shades, but that didnt help.

tried to leave 0x00, and replacing 0xff to 0x01, but I guess you meant the icon.

Code:
# https://refit.sourceforge.net/info/vollabel.html
# The image data is interpreted as indices into a standard Macintosh 256 color palette.
# However, the firmware in Intel Macs only supports the 16 indices that are pure grey.
# All other values are mapped to white. The 16 grey values, from white to black:
# 00, f6, f7, 2a, f8, f9, 55, fa, fb, 80, fc, fd, ab, fe, ff, d6


# Specify replacement values
# line 1: value -> index
# line 2: index -> value

replacements=("00:01" "f6:02" "f7:03" "2a:04" "f8:05" "f9:06" "55:07" "fa:08" "fb:09" "80:0a" "fc:0b" "fd:0c" "ab:0d" "fe:0e" "ff:0f" "d6:10"\
              "10:00" "0f:f6" "0e:f7" "0d:2a" "0c:f8" "0b:f9" "0a:55" "09:fa" "08:fb" "07:80" "06:fc" "05:fd" "04:ab" "03:fe" "02:ff" "01:d6")











(fiddled with inverting the .ppm gives at least 100% white, but thats a new story)
 

joevt

Contributor
Jun 21, 2012
6,660
4,078
Here's a script to create a BMP using the .disk_label as an alpha mask. You specify a color for the text.

Code:
le () { local n; n=$(printf "%08x" $(($1))); printf "%s" "${n:6:2}${n:4:2}${n:2:2}${n:0:2}"; }

convert_label_bmp () {
	local color="$1"
	local thelabel="$2"
	local thedest="$3"
	if [[ ! -f $thelabel ]]; then
		printf '# Disk label "%s" does not exist.\n' "$thelabel"
		return 1
	fi
	if [[ -z $thedest ]]; then
		thedest="$thelabel.bmp"
	fi

	local contents="$(xxd -c 99999999 -p "$thelabel")"
	local width=$((0x${contents:2:4}))
	local height=$((0x${contents:6:4}))
	echo "
		424d $(le $((14 + 40 + 16 + width * height * 4))) 00000000 $(le $((14 + 40 + 16)))
		$(le $((40 + 16))) $(le $width) $(le $height) 0100 2000 03000000
		$(le $((width * height * 4))) $(le 2835) $(le 2835) 0000000000000000
		0000FF00 00FF0000 FF000000 000000FF $(
			perl -pE 's/(.{'$(($width * 2))'})/$1\n/g;' <<< "${contents:10}" |
			perl -E 'print reverse <>' |
			color=$color perl -E '
				my %con = qw(
					00 00 f6 11 f7 22 2a 33 f8 44 f9 55 55 66 fa 77
					fb 88 80 99 fc aa fd bb ab cc fe dd ff ee d6 ff
				);
				while (<>) { s/(\w\w)/
					substr($ENV{color},4,2) . substr($ENV{color},2,2) . substr($ENV{color},0,2) . $con{$1}
					/eg; print $_;
				}
			'
		)
	" | xxd -p -r > "$thedest"
}

You run it like this:
Code:
thelabel=/System/Volumes/Preboot/46F1EA55-9F1B-4B09-963E-D17066406B13/System/Library/CoreServices/.disk_label_2x

convert_label_bmp "FF0000" "$thelabel" /tmp/label_red.bmp
convert_label_bmp "00FF00" "$thelabel" /tmp/label_green.bmp
convert_label_bmp "0000FF" "$thelabel" /tmp/label_blue.bmp
convert_label_bmp "FFFFFF" "$thelabel" /tmp/label_white.bmp # for dark mode
convert_label_bmp "000000" "$thelabel" /tmp/label_black.bmp # for light mode

You can view the result in BBEdit.app or Preview.app, either of which will let you change the background color.
Code:
bbedit /tmp/label_*.bmp
open -a Preview.app /tmp/label_*.bmp

I don't know why the BMP doesn't open with QuickView in the Finder. Maybe you can try that to see if you have the same problem.


I invert the original .disk_label_2x by byte swaps and convert that with OpenCore disklabel to .ppm by byte swapping the darkest black to the whitest white. Did the step to replace first to index bytes to adjust the grey shades, but that didnt help.
Oh, I didn't think about ppm. Maybe that would be better than BMP. You would need to use the .pam type.
https://en.wikipedia.org/wiki/Netpbm

tried to leave 0x00, and replacing 0xff to 0x01, but I guess you meant the icon.

Code:
# https://refit.sourceforge.net/info/vollabel.html
# The image data is interpreted as indices into a standard Macintosh 256 color palette.
# However, the firmware in Intel Macs only supports the 16 indices that are pure grey.
# All other values are mapped to white. The 16 grey values, from white to black:
# 00, f6, f7, 2a, f8, f9, 55, fa, fb, 80, fc, fd, ab, fe, ff, d6


# Specify replacement values
# line 1: value -> index
# line 2: index -> value

replacements=("00:01" "f6:02" "f7:03" "2a:04" "f8:05" "f9:06" "55:07" "fa:08" "fb:09" "80:0a" "fc:0b" "fd:0c" "ab:0d" "fe:0e" "ff:0f" "d6:10"\
              "10:00" "0f:f6" "0e:f7" "0d:2a" "0c:f8" "0b:f9" "0a:55" "09:fa" "08:fb" "07:80" "06:fc" "05:fd" "04:ab" "03:fe" "02:ff" "01:d6")

(fiddled with inverting the .ppm gives at least 100% white, but thats a new story)
My current scripts make these translations:
Code:
00 => 00
f6 => 11
f7 => 22
2a => 33
f8 => 44
f9 => 55
55 => 66
fa => 77
fb => 88
80 => 99
fc => aa
fd => bb
ab => cc
fe => dd
ff => ee
d6 => ff
I don't think there's a good way to do an inversion with transparency without knowing the background color because we are drawing antialised text which needs to blend the background and foreground colors around the edges of the text.

So the image needs to be treated as an alpha mask (like my BMP solution) or you need to remove transparency (like my TIFF solution).
The PPM seems to be drawn like the BMP (with transparency), but the forground color is always black. Does that mean it's using the PAM type? I haven't looked at the Open Core disklabel command.
 
  • Like
Reactions: Macschrauber

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
Here's a script to create a BMP using the .disk_label as an alpha mask. You specify a color for the text.

Code:
le () { local n; n=$(printf "%08x" $(($1))); printf "%s" "${n:6:2}${n:4:2}${n:2:2}${n:0:2}"; }

convert_label_bmp () {
    local color="$1"
    local thelabel="$2"
    local thedest="$3"
    if [[ ! -f $thelabel ]]; then
        printf '# Disk label "%s" does not exist.\n' "$thelabel"
        return 1
    fi
    if [[ -z $thedest ]]; then
        thedest="$thelabel.bmp"
    fi

    local contents="$(xxd -c 99999999 -p "$thelabel")"
    local width=$((0x${contents:2:4}))
    local height=$((0x${contents:6:4}))
    echo "
        424d $(le $((14 + 40 + 16 + width * height * 4))) 00000000 $(le $((14 + 40 + 16)))
        $(le $((40 + 16))) $(le $width) $(le $height) 0100 2000 03000000
        $(le $((width * height * 4))) $(le 2835) $(le 2835) 0000000000000000
        0000FF00 00FF0000 FF000000 000000FF $(
            perl -pE 's/(.{'$(($width * 2))'})/$1\n/g;' <<< "${contents:10}" |
            perl -E 'print reverse <>' |
            color=$color perl -E '
                my %con = qw(
                    00 00 f6 11 f7 22 2a 33 f8 44 f9 55 55 66 fa 77
                    fb 88 80 99 fc aa fd bb ab cc fe dd ff ee d6 ff
                );
                while (<>) { s/(\w\w)/
                    substr($ENV{color},4,2) . substr($ENV{color},2,2) . substr($ENV{color},0,2) . $con{$1}
                    /eg; print $_;
                }
            '
        )
    " | xxd -p -r > "$thedest"
}

You run it like this:
Code:
thelabel=/System/Volumes/Preboot/46F1EA55-9F1B-4B09-963E-D17066406B13/System/Library/CoreServices/.disk_label_2x

convert_label_bmp "FF0000" "$thelabel" /tmp/label_red.bmp
convert_label_bmp "00FF00" "$thelabel" /tmp/label_green.bmp
convert_label_bmp "0000FF" "$thelabel" /tmp/label_blue.bmp
convert_label_bmp "FFFFFF" "$thelabel" /tmp/label_white.bmp # for dark mode
convert_label_bmp "000000" "$thelabel" /tmp/label_black.bmp # for light mode

You can view the result in BBEdit.app or Preview.app, either of which will let you change the background color.
Code:
bbedit /tmp/label_*.bmp
open -a Preview.app /tmp/label_*.bmp

I don't know why the BMP doesn't open with QuickView in the Finder. Maybe you can try that to see if you have the same problem.



Oh, I didn't think about ppm. Maybe that would be better than BMP. You would need to use the .pam type.
https://en.wikipedia.org/wiki/Netpbm


My current scripts make these translations:
Code:
00 => 00
f6 => 11
f7 => 22
2a => 33
f8 => 44
f9 => 55
55 => 66
fa => 77
fb => 88
80 => 99
fc => aa
fd => bb
ab => cc
fe => dd
ff => ee
d6 => ff
I don't think there's a good way to do an inversion with transparency without knowing the background color because we are drawing antialised text which needs to blend the background and foreground colors around the edges of the text.

So the image needs to be treated as an alpha mask (like my BMP solution) or you need to remove transparency (like my TIFF solution).
The PPM seems to be drawn like the BMP (with transparency), but the forground color is always black. Does that mean it's using the PAM type? I haven't looked at the Open Core disklabel command.

Yes :)

The convert_label_bmp function solved the headache around the drawing of the .disk_icon_2x file. I can use it without further converting giving the bmp file directly as an icon to AppleScript's Display Dialog.

Am so glad I don't need to spend more nights on this topic.

Screenshot 2024-01-15 at 20.18.04.png

Screenshot 2024-01-15 at 20.18.50.png



I attach some .ppm file OpenCore's disklabel is creating. But I don't need that no more, your converter works way better for this.
 
Last edited:

joevt

Contributor
Jun 21, 2012
6,660
4,078
Are the BMPs generated by my script viewable in the Finder with QuickView? Select a BMP and press spacebar. I think I need to reboot or something to get it to be viewable with QuickView on my Skylake Hackintosh running Monterey. The same thing is happening with the PPMs. The BMPs and PPMs are viewable with QuickView on my other Macs.

Are you changing the color between black and white when using convert_label_bmp depending on the current ligh/dark mode setting or does the API handle that for you?
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
Are the BMPs generated by my script viewable in the Finder with QuickView? Select a BMP and press spacebar. I think I need to reboot or something to get it to be viewable with QuickView on my Skylake Hackintosh running Monterey. The same thing is happening with the PPMs. The BMPs and PPMs are viewable with QuickView on my other Macs.

Are you changing the color between black and white when using convert_label_bmp depending on the current ligh/dark mode setting or does the API handle that for you?

I can see the generated icons in QuickView, both ppm and your bmp:
Screenshot 2024-01-16 at 00.05.55.png

I need to detect light and dark mode, otherwise I get that barely visible dark icon:

Screenshot 2024-01-16 at 00.09.19.png

so it seems it just draws the picture, same behaviour as with the ppm generated by OpenCore's disklabel.

Detecting dark mode is: If defaults read -g AppleInterfaceStyle contains "dark", btw.


so the logic is

Code:
on disk_label_editor(the_path)
.
.
  if is_dark_mode() then -- convert .disk_label_2x file to /tmp
      set color_mask to "FFFFFF"
          else
      set color_mask to "000000"
  end if
		
  do shell script my convert_label_bmp & space & color_mask & space & (quoted form of disk_label_file_2x) & space & tmp_icon
.
.
.
end disk_label_editor


on is_dark_mode()
	try
		return ((do shell script "defaults read -g AppleInterfaceStyle") contains "Dark")
	on error
		return false -- Assume light mode if an error occurs or the key doesn't exist
	end try
end is_dark_mode
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
btw: makemultilinedisklabel from joevt is added:

Screenshot 2024-01-16 at 00.33.45.png



so another bleeding edge version attached:

- disk_label rendering fixed in dark mode (thanks to joevt), the size is not adjustable due to limits of AppleScript GUI
- multi line disk_labels generating added (thanks to joevt)
- more logging
- more info in the disk label editor


may need xattr -cr ~/Downloads/Preboot\ fixer\ \&\ renamer\ 16-1.app
 
Last edited:
  • Like
Reactions: startergo

joevt

Contributor
Jun 21, 2012
6,660
4,078
Detecting dark mode is: If defaults read -g AppleInterfaceStyle contains "dark", btw.
Does that work for auto mode?

btw: makemultilinedisklabel from joevt is added:
Evil and fun :)

so another bleeding edge version attached:

- disk_label rendering fixed in dark mode (thanks to joevt), the size is not adjustable due to limits of AppleScript GUI
- multi line disk_labels generating added (thanks to joevt)
- more logging
- more info in the disk label editor

may need xattr -cr ~/Downloads/Preboot\ fixer\ \&\ renamer\ 16-1.app
Seems to work. I don't know if newline in .contentDetails works. You may need to replace newlines with spaces (see how Open Core displays it). Or you may want two different text input fields - one for the label image and another for the text only .contentDetails files. Hide the second text input field if a "Use seperate text for .contentDetails" checkbox or radio button is unselected.

Actually, it looks like makemultilinedisklabel creates both .disk_label files (2x and not 2x) and also a .disk_label.contentDetails file with newlines replaced by spaces. Maybe you are overwritting the .disk_label.contentDetails file that it creates with your own version?

makemultilinedisklabel doesn't make a .contentDetails file which might be specific to Open Core? I don't know which part of macOS (if any) makes .disk_label.contentDetails or .contentDetails files. So maybe modify makemultilinedisklabel to also create the .contentDetails file.

It seems the modification date of the Preboot fixer & renamer 16-1.app doesn't get updated to match the latest changed file? Maybe use a touch command to update the modification date.
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
Does that work for auto mode?

guess so ,my MP3,1 is configured that way, but I check closer this weekend as I am not on the box at daytime.

set auto on my other machine and the string contained dark. So it works

Code:
#on Big Sur:

#light
bash-3.2$ defaults read -g AppleInterfaceStyle
2024-01-16 20:27:34.556 defaults[4907:35229] 
The domain/default pair of (kCFPreferencesAnyApplication, AppleInterfaceStyle) does not exist

#dark
bash-3.2$ defaults read -g AppleInterfaceStyle
Dark

#auto, dark mode set by local time
bash-3.2$ defaults read -g AppleInterfaceStyle
Dark



Evil and fun :)


Seems to work. I don't know if newline in .contentDetails works. You may need to replace newlines with spaces (see how Open Core displays it). Or you may want two different text input fields - one for the label image and another for the text only .contentDetails files. Hide the second text input field if a "Use seperate text for .contentDetails" checkbox or radio button is unselected.

have seen that, I take your function when an ascii code 10 is in, and OpenCore disklabel if not. The reason is that OpenCore disklabel is faster, it does not make temporary disk images.
Actually, it looks like makemultilinedisklabel creates both .disk_label files (2x and not 2x) and also a .disk_label.contentDetails file with newlines replaced by spaces. Maybe you are overwritting the .disk_label.contentDetails file that it creates with your own version?

makemultilinedisklabel doesn't make a .contentDetails file which might be specific to Open Core? I don't know which part of macOS (if any) makes .disk_label.contentDetails or .contentDetails files. So maybe modify makemultilinedisklabel to also create the .contentDetails file.

I create the .disk_label.contentDetails and .contentDetails, after the bleeding edge version I have seen that those files contain a newline and yours not. I will swap 10 with space.

.contentDetails is for OpenCore's menu. Needs tests what it prefers, icon or .contentDetails
It seems the modification date of the Preboot fixer & renamer 16-1.app doesn't get updated to match the latest changed file? Maybe use a touch command to update the modification date.

Yes, that's because I open the script package and edit the script file. This is because the embedded tools sometimes gets deleted when Script Editor / Script Debugger writes a new .app package.

Also I discovered a mad bug with choose from list, if built on, lets say Mojave it will cut long lines when the script runs in Big Sur and later. Stuff noone needs...

If I dont forget I touch released versions, also edit the plist to match versions.
 
Last edited:

joevt

Contributor
Jun 21, 2012
6,660
4,078
have seen that, I take your function when an ascii code 10 is in, and OpenCore disklabel if not. The reason is that OpenCore disklabel is faster, it does not make temporary disk images.
I use the temporary disk image so bless won't have any side effects with other drives.

You could replace the calls to bless in makemultilinedisklabel with calls to OpenCore's disklabel to create the multiline disk label.
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
I use the temporary disk image so bless won't have any side effects with other drives.

You could replace the calls to bless in makemultilinedisklabel with calls to OpenCore's disklabel to create the multiline disk label.

OpenCore disklabel can not create multi line disk labels (I use ocdisklabel as tool name)

Code:
ocdisklabel -e test$'\n'test a b # echo test newline test to file a and file b (2x)
ocdisklabel -d b test.ppm # decode file b to test.ppm
open test.ppm
Screenshot 2024-01-17 at 01.04.33.png

but thats ok. It is just 3 seconds or so, for the one who makes a multi line name.
 

joevt

Contributor
Jun 21, 2012
6,660
4,078
OpenCore disklabel can not create multi line disk labels (I use ocdisklabel as tool name)
Neither can bless.
makemultilinedisklabel uses bless for each line and then combines the lines into a single image.
So what I am suggesting is to replace the call to bless with a call to ocdisklabel, then you don't need to temporary disk image stuff.
 
Last edited:
  • Like
Reactions: Macschrauber

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
adjusted it to use OpenCore's disklabel

fun fact with AppleScript worth to mention:
When you use do shell script in AppleScript, it runs the command in a new shell environment, and the default working directory for that shell is the root directory /.

So need to cd into dirname $0 or add the path when calling other tools.


Bash:
#!/bin/bash
# by joevt May 10, 2023
# modified by Macschrauber Jun 17, 2024
# to use OpenCore disklabel
# and to adjust working path, when called by AppleScript




# dump disk_label file
dump_label () {
    local contents
    contents=$(xxd -p -c99999 "$1"); echo "${contents:10}" | perl -pe "s/(..)/\1 /g;s/00/../g;s/ //g;s/(.{$((0x${contents:2:4}*2))})/\1\n/g"
}


makemultilinedisklabel () {

    if (( $# != 2 )); then
        echo "# error: not enough arguments" 1>&2
        echo "# usage: makemultilinedisklabel destinationpath disklabellines" 1>&2
        return 1
    fi
    local folder="$1"
    if [[ ! -d $folder ]]; then
        echo '# error: "'"$folder"' is not a folder' 1>&2
        echo "# usage: makemultilinedisklabel destinationpath disklabellines" 1>&2
        return 1
    fi
    local lines="$2"
    local alllines=""
    local alllines2x=""
    local tempfolder=""
    tempfolder="$(mktemp -d /tmp/makemultilinedisklabel.XXX)"
    


    IFS=$'\n'
    local linenum=0
    local theline=""
    local theoneline=""
    for theline in $(echo "$lines"); do
        ./disklabel -e "$theline" "$tempfolder/.disk_label" "$tempfolder/.disk_label_2x"
        if (( linenum )); then
            alllines+="$(dump_label "$tempfolder/.disk_label" | sed '1,/[^.]/ {/^[.]*$/d; }')"$'\n'
            alllines2x+="$(dump_label "$tempfolder/.disk_label_2x" | sed '1,/[^.]/ {/^[.]*$/d; }')"$'\n'
            theoneline+=" $theline"
        else
            alllines+="$(dump_label "$tempfolder/.disk_label")"$'\n'
            alllines2x+="$(dump_label "$tempfolder/.disk_label_2x")"$'\n'
            theoneline="$theline"
        fi
        ((linenum++))
    done

    local suffix=""
    local thelines=""
    for suffix in "" "_2x"; do
        [[ -z $suffix ]] && thelines="$alllines" || thelines="$alllines2x"

        local linewidths=""
        local maxlinewidth=""
        linewidths="$(echo "${thelines}" | tr '0-9a-f' '.' | sort -ur)"
        maxlinewidth=$(echo "$linewidths" | sed -n '1p')
        linewidths=$(echo "$linewidths" | sed '1d')

        local centercommands=""
        local linewidth=""
        for linewidth in $(echo "$linewidths"); do
            local left=${maxlinewidth:0:(${#maxlinewidth}-${#linewidth})/4*2}
            local right=${maxlinewidth:0:(${#maxlinewidth}-${#linewidth}-${#left})}
            centercommands+="s/^(${linewidth})$/$left\1$right/; "
        done
        thelines=$(echo "$thelines" | sed -E "$centercommands s/\./0/g")
        printf "01%04x%04x$thelines" $((${#maxlinewidth} / 2)) "$(echo "$thelines" | wc -l)" | xxd -p -r > "$tempfolder/disk_label$suffix"
        
        # EFI file system converts schg flag to uchg flag, so we set both to no
        [[ -f "$folder/.disk_label$suffix" ]] && {
            sudo chflags noschg,nouchg "$folder/.disk_label$suffix"
        }
        sudo cp "$tempfolder/disk_label$suffix" "$folder/.disk_label$suffix"
    done

    [[ -f "$folder/.disk_label.contentDetails" ]] && {
        sudo chflags noschg,nouchg "$folder/.disk_label.contentDetails"
    }
    theoneline="${theoneline/🄳/ [D]}"
    theoneline="${theoneline/🄿/ [P]}"
    theoneline="${theoneline/🅁/ [R]}"
    theoneline="${theoneline/🄱/ [B]}"
    theoneline="${theoneline//  / }"
    printf "%s" "$theoneline" > "$tempfolder/disk_label.contentDetails"
    sudo cp "$tempfolder/disk_label.contentDetails" "$folder/.disk_label.contentDetails"
}


# When you use do shell script in AppleScript, it  runs the command in a new shell environment,
# and the default working directory for that shell is the root directory /.
base_of_me=$(dirname "$0")
cd "$base_of_me"

makemultilinedisklabel "$1" "$2"
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,784
1,379
Germany
joevt makemultilinedisklabel with OpenCore's Disklabel works also for ESPs.

The original makemultilinedisklabel with disk images had not done ESPs' disk labels.

I adapted the disk label editor to the Label ESP scripts as well.

Disk label editor.png

Tested on MBP11,1:
native BootPicker showed OS and ESP with 2 lines generated by joevt makemultilinedisklabel

OpenCore showed 1 line, so it reads the text file.
 

joevt

Contributor
Jun 21, 2012
6,660
4,078
adjusted it to use OpenCore's disklabel

fun fact with AppleScript worth to mention:
When you use do shell script in AppleScript, it runs the command in a new shell environment, and the default working directory for that shell is the root directory /.

So need to cd into dirname $0 or add the path when calling other tools.
By other tools you mean those in your Preboot Fixer package that your makemultilinedisklabel script depends on which is just the disklabel command.

Another way to do it without changing the working directory is set a $disklabel variable like this:
disklabel="$(dirname "$0")/disklabel"

Then run disklabel like this:
"$disklabel" ...

joevt makemultilinedisklabel with OpenCore's Disklabel works also for ESPs.

The original makemultilinedisklabel with disk images had not done ESPs' disk labels.
The original should work with any folder. Shouldn't matter if its on an ESP or not. What's the problem? Error message? Is it not storing a .disk_label file?

Startup Manager on MacPro3,1 ignores disk labels for Boot Camp disks (label is "Windows" without antialiasing) and EFI volumes (label is "EFI Boot" without antialiasing). This is why you should include a .VolumeIcon.icns for EFI volumes.

Tested on MBP11,1:
native BootPicker showed OS and ESP with 2 lines generated by joevt makemultilinedisklabel
I guess MBP11,1 is 2014 which is newer than my MacPro3,1 (2008) and therefore has code to display .disk_label image instead of just "EFI Boot".

OpenCore showed 1 line, so it reads the text file.
For OpenCore, there's a setting bit OC_ATTR_USE_DISK_LABEL_FILE for PickerAttributes to make it use .disk_label image instead of .contentDetails text.
 
  • Like
Reactions: Macschrauber
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.