Getting and setting PPD options via command line for use with lpadmin in OS X

UPDATE – Script now will convert CR to LF line endings for better reliability with old PPDs

There are some good hints for adding printers via the command line with lpadmin: Managing multiple printers via the command line

However, there is still confusion surrounding the setting of printer options from the command line, as a poster to Debian bugs pointed out back in 2006: lpoptions documentation doesn’t. After doing some testing, here’s the two main takewaways:

  • If you use lpadmin and specify options with “-o” the PPD is altered and OS X will recognize the options for the printer.
  • However, if you setup the printer using lpadmin without any options and later use lptoptions to set the options, they are not written to the PPD and the GUI is unaware of the printer’s options.

more helpful hints about lpadmin and lpoptions:

lpoptions -p printername -l

  • Prints PPD options, “Default” is filtered out from option name (compared to looking at the raw PPD)
  • It uses a colon when reporting key value pairs, however replace that with an equals sign when specifying an option
  • The option name stops at the first slash
  • Example: The duplex option for HP printers will output like this “HPOption_Duplexer/Duplex Unit: *True False”
    When specified as a “-o” option it would be “HPOption_Duplexer=True”

lpadmin … -o this=that

  • Alters the ppd that is placed in /etc/cups/ppd/ when the printer is installed

Unhelpful things:

lpoptions -p printername

  • These are NOT the PPD options you want to set

lpoptions -o

  • Only writes options to: /private/etc/cups/lpoptions (run with sudo) or ~/.cups/lpoptions (run as current user), GUI apps are unaware of these options


The following script compares the original and the newly installed PPD to generate the options syntax to be used with lpadmin: 

The main magic in this script is a little diff and sed:

diff "$originalfile" "$newfile" | grep "> [*]Default" | sed 's/> [*]Default/-o /g' | sed 's/: /=/g'

Script Workflow

  • Copy and paste the script into TextWrangler (or download ppdOptionsDiff.command), save with a .command extension and it will automatically take care of the executable bit
  • Setup your printer via the Printers Preference Pane in the GUI.
  • Look in /etc/cups/ppd and find the newest .ppd (it will be named as the printer)
  • Locate the original .ppd.gz (or .ppd) in /Library/Printers/PPDs/Contents/Resources/, usually the printer ppd is easily found by name, but some like Canon have some cryptic filenames, so look inside the /etc/cup/ppd file, the “PCFileName” variable sometimes helps to determine the file name
  • Run the script given below, it will ask you to drag in the original and the modified ppds. Out will come the “-o” options for use with lpadmin

You can also run the script with the original and modified file paths as arguments and the string will be output

The script “ppdOptionsDiff.command“:

#!/bin/bash
[ -f /tmp/debug ] && set -x
#ppd option maker

#help
if [ "$1" == "-h" ]; then
	echo "$(basename $0) compares two ppds and outputs the differences as a string for use in lpadmin"
	echo "Usage: $(basename $0) [original_ppd] [new_ppd]"
	exit
fi

#check for parameter if not ask
if [ -z "$1" -o -z "$2" ]; then
	clear;
	echo "Drag in the unmodified PPD from /Library/Printers/PPDs/Contents/Resources:"
	open /Library/Printers/PPDs/Contents/Resources
	while [ -z "$originalfile" ]; do
	read originalfile
	done

	echo "Drag in the PPD from /etc/cups/ppd:"
	open /etc/cups/ppd
	while [ -z "$newfile" ]; do
	read newfile
	done
#else just take the arguments
elif [ -n "$1" -o -n "$2" ]; then
	newfile="$2"
	originalfile="$1"
fi

#make a temp file of the original to compare
#strip off path and extension for temp file name
tempOriginalFile="/tmp/$(basename "$originalfile" .gz)"

#if file is compressed expand
if [ "${originalfile##*.}" == "gz" ]; then
	#uncompress
	IFS=$'\n\t'
	#gunzip to temp file
	gunzip < "$originalfile" > "$tempOriginalFile"
else
#just make a copy
cp "$originalfile" "$tempOriginalFile"
fi

#change line endings from CR to LF (diff fails unless this is done)
sed -e $'s/\\\r/\\\n/g' -i '' "$tempOriginalFile"

#make a temp file of the new file to compare
#strip off path
tempNewFile="/tmp/$(basename "$newfile")"
cp "$newfile" "$tempNewFile"

#change line endings from CR to LF (diff fails unless this is done)
sed -e $'s/\\\r/\\\n/g' -i '' "$tempNewFile"

#test for file existence
if [ ! -f "$tempOriginalFile" ]; then echo "$tempOriginalFile is not a valid path"; exit; fi 
if [ ! -f "$tempNewFile" ]; then echo "$tempNewFile is not a valid path"; exit; fi 

#create options list by diffing and filtering
optionList=$(diff "$tempOriginalFile" "$tempNewFile" | grep "> [*]Default" | sed 's/> [*]Default/-o /g' | sed 's/: /=/g')

#print out the options with no line breaks
IFS=$'\n\t'
if [ ! -z "$optionList" ]; then
	for option in $optionList; do 
		echo -n "$option "
	done
	echo
else
	echo "No differences"
fi

#delete the temp filess
rm "$tempOriginalFile" "$tempNewFile"

exit

Example (with pathnames provided as arguments, otherwise runs in interactive mode):

$ ./ppdOptionsDiff.command /Library/Printers/PPDs/Contents/Resources/HP\ LaserJet\ 5200.gz /private/etc/cups/ppd/PRINTERNAME.ppd

-o HPOption_Tray3=Tray3_500 -o HPCollateSupported=True -o HPOption_Duplexer=True -o HPOption_Disk=RAMDisk

Use the generated string in lpadmin to set the printer options, like this example:

lpadmin -p "Ye_Olde_LaserJet" -D "Ye Olde LaserJet" -E -v socket://x.x.x.x -P /Library/Printers/PPDs/Contents/Resources/HP\ LaserJet\ 5200.gz -L "Location is in a closet in a sub-basement, good luck" -D -o HPOption_Tray3=Tray3_500 -o HPCollateSupported=True -o HPOption_Duplexer=True -o HPOption_Disk=RAMDisk -o printer-is-shared=false

The documentation from man lpadmin is a bit obtuse and lacking. For example: -E will enable the printer (essential!) except when used before -p or -d in those cases it forces encryption, so watch out! Also, in the man page it shows -h server[:port] but -h is not documented anywhere in there and I have never used it. Rather, the -v option should be used with a URL like lpd://, socket:// (HP), ipp://, etc.. if you want to get a listing of the protocols run lpinfo -v this will even do a look around with Bonjour to see what’s on the network (they are dnssd://). The -p option is the CUPS queue name, it does not allow spaces, whereas the -D option is the “friendly name” that a user will see in macOS, you can set some location text with -L and finally just tack all the -o options on the end. -o printer-is-shared=false will keep the printer from being broadcast if you turn on Printer Sharing (or if a user accidentally turns it on)

Make a Snow Leopard 10.6.7 Installer Disc from a Mac Restore Disc

So there was this hint the other day at MacWorld’s OS X Hints site:
10.6: Make a universal 10.6.7 Snow Leopard installer – Mac OS X Hints

It was a very useful hint for hacking together a retail Snow Leopard disc (10.6.0/10.6.3 ) and the newest system specific restore disc (10.6.7 for iMacs and MacBook Pros) to make a “universal” 10.6.7 disc that would work on new and old machines alike, that are qualified to run Snow Leopard. Useful not only for techs who need a one disc does it allbut others who might lack bandwidth for updates since this cuts down on some Software Update downloads (10.6.8 is only a smaller “delta” update this way.)

So, it was a good hint because it got to the heart of the matter, that OSInstall.mpkg was where the script logic determines if your machine is qualified for the restore. However using the original 10.6 disc and copying over all the old printer drivers is a little too kludgy for me, the less donethe better. I knew there had to be a more elegant way…

Voila – this bash script strives for automagic: it reads in your restore disc, prompts you to grab your disc and pop in a blank DVD, then modifies the install logic, and burns the disc you can use on all your Snow Leopard elligible Macs (P.S. Don’t steal OS X). It hasn’t been QC’d or QA’d beyond a few runs using one set of 10.6.7 restore disc, but I hope it comes in handy for some Mac tech out there somewhere who is in a pinch and needs to restore Snow Leopard – if only to get App Store on a machine and then up to 10.7 or 10.8!

makeUniversalSnowLeoDisc.command

#!/bin/bash
clear

destination=~/Desktop/Mac\ OS\ X\ Install\ DVD

#make destination folder
[ ! -d "$destination" ] && mkdir "$destination"

#make sure disc is in drive
while [ ! -d /Volumes/Mac\ OS\ X\ Install\ DVD ] ; do
echo Please insert Mac OS X Install DVD and press Enter
read
done

#get device node for block copy
device=$(diskutil info /Volumes/Mac\ OS\ X\ Install\ DVD/ | grep Node | cut -f2 -d:)

#create disk image from device (retains Finder window custom background)
echo "Creating Disc image at $destination, please wait..."
/usr/bin/hdiutil create -srcdevice $device -format UDRW "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

#disk image using source folder (loses custom Finder background)
#/usr/bin/hdiutil create -srcfolder /Volumes/Mac\ OS\ X\ Install\ DVD/ -format UDRW "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

#eject media
/usr/bin/drutil eject

#tell user to take out disc
echo -e $'\a'$'\a'$'\a'$'\n'"Please Remove the disc and press Enter"$'\n'
read

echo "Modifying Image"
#mount r/w image
hdiutil attach "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

#expand OSINstall.mpkg
/usr/sbin/pkgutil --expand /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.mpkg /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded

#modify Distribution script in place with no backup
/usr/bin/sed -i '' "s/modelProp\ \=\=\ hwbeSupportedMachines\[i\]/1/g" /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded/Distribution

#modify Distribution script in place with backup (for sissies)
#/usr/bin/sed -i '.original' "s/modelProp\ \=\=\ hwbeSupportedMachines\[i\]/1/g" /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded/Distribution

#remove original OSInstall.mpkg package
/bin/rm -rf /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.mpkg

#flatten new package
/usr/sbin/pkgutil --flatten /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.mpkg

#remove expanded folder
/bin/rm -rf /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded

### image is now ready to be burned ###

#eject disk image
hdiutil eject /Volumes/Mac\ OS\ X\ Install\ DVD/

#burn disc image
/usr/bin/drutil burn "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

echo -e $'\a'$'\a'$'\a'$'\n'"Disc Complete, Please Remove the disc"$'\n'

Lion’s grey sidebar is a Jedi mind trick

These aren't the files you're looking for...

And a poor attempt at a Jedi mind trick at that. With the now grey and lifeless sidbar in Lion Apple is trying to visually say: “these aren’t the files or folders you’re looking for”. It’s as if they want us to become so turned-off to this grey apocalyptic version of the sidebar that we yearn for iCloud where our data lives in the apps and those pesky file and folder structures cease to have any relevance in our workflow.

Reality check Apple, you won’t change our habits overnight, nor overturn what is a completely valid way of working with your computers.  You will not endear us to the iCloud experience by also crippling the Finder’s look and feel. Although I do thank you for returning the ability to have large icons in the sidebar, which you took away in 10.5, the grey-ification of the icons and the exile of Devices to the bottom of the list has truly hobbled any usefulness the Finder had. Oh, add the fact that mounted volumes no longer show as a Device, but rather you have to add them manually to favorites has also irked me. Why should I have to open up Shared, click the server then find the volume I want. It’s ridiculous when you couple that with having the default Finder behavior to not show mounted volumes on the desktop. Fine you hate files, folders and drives, we get it, but not all of us agree… “the rest of us”, as it were.

Here’s a compromise I could live with Apple:

At least give us a choice Apple!

Thankfully, a very bright Mac developer has made a plugin to return color to the Finder sidebar. Now I normally do not like using SIMBL plugins because code injection and method swizzling makes me nervous. But having color on the sidebar is worth it. You can find all the info for doing this at OS X Daily along with installation tips.

Colorful Sidebar by CVZ

So, file those Bug Reports with Apple and let them know their Jedi mind trick isn’t going to work. These are the files and folders we’re looking for and color would greatly help us find them. (I’d consider this a regression fix rather than a feature request.)

Postscript on (not) using Finder:
A quick note for the purists out there who don’t even run Finder. You intrepid folks take a road less travelled but not one that not everyone wants to embark down. Now, Rick of Rixstep will argue that Finder is an and abhorrent holdover from OS 9 that should have gotten the axe or at the least been completely recoded into 100% Cocoa, all of its Carbon cruft put out to pasture, its very existence is retarding OS X, and to run Finder on your system is akin to self-trepanation. OK — fair enough actually on most points! :D However, until someone else comes along with a Finder replacement that is 100% Cocoa and has full feature parity, then we put up with the Finder. (And most businesses would be loathe to spend money on licenses for Finder replacements like XFile or PathFinder, it’s hard enough to get them to spend the extra dough up-front for a Mac!) Wah wah :/ So we commiserate with others on the discussion boards and plead our case to the Designers Gone Wild at Apple.

Make Safari find substring matches by default

So, I thought I’d tip ol’ Pierre at betalogue to an apparent bug that Safari doesn’t find substrings, only words that begin with the search string! But then his astute readers pointed out that Safari 5.1 has changed the behaviour of the Find window, if you just look close enough *blush*

Now by default in Safari 5.1, when you hit Command-F and type in a word, Safari will match words that “Start with” your search item, clicking the magnifying glass, presents you with the option to search for words that “Contain” your search phrase (this was the default search behaviour in Safari pre-5.1), and in fact clicking the magnifying glass used to step through matches. Who knew!? I’m a (Shift)/Command-G man myself.

Now how could we change this behaviour back for a few hundred users who are used to the way Safari has been functioning before Apple so elegantly altered it? Here we go!

Preference domain: com.apple.Safari
Key Name: FindOnPageMatchesWordStartsOnly
Values: Boolean, TRUE equals “Start With” and FALSE equals “Contains”.

It is a per-user preference, if the key is not present Safari defaults to “Start With” in a search. Writing the pref to the higher level /Library/Preferences/com.apple.Safari.plist will affect all users who don’t already have the key set, otherwise Safari will defer to the user’s prefs (and it can then be assumed the user is aware of the change since they clicked on the magnifying glass and altered the setting).

Here’s the defaults commands for Terminal to set Safari’s Find back to “Contains”:
All Users (who don’t have it set in their prefs)
defaults write /Library/Preferences/com.apple.Safari FindOnPageMatchesWordStartsOnly -bool FALSE
Current User
defaults write com.apple.Safari FindOnPageMatchesWordStartsOnly -bool FALSE

There you go that’ll get things back the way they were, make sure it’s all on one line, the theme seems to like to wrap code, but a copy/paste does not include the newline.

Restore previous Safari version from .SafariArchive.tar.gz

Did that new Safari update break something? Want your old version back?
Simple. Thanks to Apple’s prescient yet secretive engineers, there’s a way.
Let me show you.

When Safari does an upgrade it saves the previous version in this location:
/Library/Application\ Support/Apple/.SafariArchive.tar.gz

To restore we just need to tell tar to expand the archive to the root folder:
sudo tar -xvf /Library/Application\ Support/Apple/.SafariArchive.tar.gz -C /

To be complete, delete the receipt from /var/db/receipts, in this case it is Safari 5.1
sudo rm -rf /private/var/db/receipts/com.apple.pkg.Safari51SnowLeopard.*

Reboot. (since we’ve just replaced a whole bunch of public and private frameworks the OS uses)

Done.
(Whew. This will fix the early Safari 5.1 adopters at work who now can’t use our Java based timesheet app since upgrading!)

myXProtectStatus

myXProtectStatus – A drop down status menulet for XProtect, showing date, version, and threats protected against. Written in bash, and wrapped with Platypus, it is informational only, so don’t ask me to add some menu item to do something, it just reports. However I did add the Command Line and GUI ways to update XProtect in the output, so it’s of some use for that. When run, it’ll reside in your menu bar and call a script inside itself each time it runs. Tuck it away somewhere, add it to your loginitems. Check it every once and a while…

Screenshot of myXProtectStatus:

Other notes: I pipe the output of the threat list though /usr/bin/uniq, because while Hell.RTS has three different signatures it retains the same name in each and it seemed redundant to list all of them out! So all recurring names will be reduced to one entry.

The menu bar icon: it’s an X with a grey picket fence around it, I made it tiny… then realized I need an icon for the App too rather than Platypus’ so I sized it up, it’s fugly, but you’ll never see it! :)

Bonus: When run as root, it will show the auto-update on/off status, which can only be determined on the command line by root.

 

WWDC 2011

Going to WWDC 2011! See you all there! (although, I got a haircut so it’s all short now and not the curls you see on the site :)) and whatever is not NDA I’ll tweet via brunerd

Advanced Safe Downloads List Tips and Tricks

So I submitted a hint for getting info about the Safe Downloads protection list, then I made a widget, now delving deeper into Safe Downloads list and the command line

Let’s look at the BOM for the update:

/Library/Preferences/com.apple.ReportMessages.domains
/Library/Preferences/com.apple.ReportMessages.v2.domains
/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.plist
/System/Library/CoreServices/MRTAgent.app
/System/Library/LaunchAgents/com.apple.mrt.uiagent.plist
/System/Library/LaunchDaemons/com.apple.mrt.plist
/System/Library/LaunchDaemons/com.apple.xprotectupdater.plist
/System/Library/PreferencePanes/Security.prefPane
/usr/libexec/MRT
/usr/libexec/XProtectUpdater

What’s interesting is after installation /usr/libexec/MRT, com.apple.mrt.plist, and com.apple.mrt.uiagent.plist delete themselves after they run?! This is odd, yes? From what it looks like MRT has a lot of pattern matching  code in it… Also notable is that in the postflight action loadMRT, the launchagent and daemon are unloaded and reloaded in the postflight actions, however the loadXProtectUpdater script does not do this. So the XProtectUpdater does not run again if you rerun the installer since launchctl will report it’s already loaded, so you’ll have to wait a day for it to check again and update as seen in com.apple.xprotectupdater.plist (86400 seconds = 1 day).

If you want to manually force an update, you can run this command:
sudo /usr/libexec/XprotectUpdater
You must run as root or else it informs you:
XprotectUpdater[pids] Unable to write new signature meta plist

You can also just toggle the preference in the Security prefpane, this causes the launchd job to be unloaded an reloaded, however from an admin POV it’s nice to have a non-GUI way to do this. Also there seems to be a bug in the prefpane so values are not written after it is open for more than 30 seconds! Come on 10.6.8! (It feels like this was Lion stuff that’s getting shoe-horned into Snow Leopard a bit earlier than they expected )

Another interesting tidbit is the actual malware list that is squirreled away here:
/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.plist

If you attempt to use the defaults command to read it you are given this:
defaults[pids] Preference plist was NOT a dictionary.
defaults[pids] Domain /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect does not exist

It seems the Apple folks have done some creative things so while this is still valid XML it is not a defaults compatible plist. The values are dictionaries stored in an array at the top level. Is this protection against script-kiddies who’d use defaults to change values in the list? While the file is root owned, one must wonder if there are safeguards to check its checksum against a server to detect unauthorized changes to it? Since admin status is enough to escalate to root using sudo (and every initial user in OS X is an admin), combine this with the fact that installer runs as root when installing a pkg, and this is something to keep an eye on… (oh right my point being this thwarts a script to list detected threats, at least easily using defaults)

And some parting advice: Turn off Open Safe Downloads in Safari! It’s an oddly bad decision by Apple, its paralells to Windows’ AutoPlay/AutoRun give me goose bumps! I don’t want a dmg opening itself up and copying out it’s pkg payload into Downloads, then auto launching it! CRAZY BAD! Malware on a platinum platter, Apple couldn’t have made it easier!

Here’s the code for turning this off in Safari, it is a per user preference:
defaults write com.apple.Safari AutoOpenSafeDownloads -bool FALSE

And so concludes this expedition, hope you learned something, and can teach me something back in the process, thanks!

Safe Downloads List Info Widget

UPDATE: The AUTOUPDATE code only works as root and so is not useful in the Dashboard environment! This has been removed from the widget.

So I slapped together a widget for the Safe Downloads commands I post at OSXHints:

Safe Downloads Info Widget

Nothing glamorous just the facts and the following code is how it gets it’s values:

defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta LastModification
defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta Version

The auto updates status took a bit more massaging:

eval $(sudo defaults read /private/var/db/launchd.db/com.apple.launchd/overrides com.apple.xprotectupdater | sed 's/ //g')
if [ ${Disabled:=0} -eq 0 ]; then
echo ON
else
echo OFF
fi

All apologies to Dashboard coding perfectionists but the calls for the widget are synchronous, and reading up on Dashboard coding best practices, Apple says a shipping widget should only use asynchronous calls for info… oh well it works well enough for me! :) Perhaps I’ll go back and throw in extra lines of code for asynchronous handlers when I can, if my widget freezes up any other widgets you can simply restart Dashboard by killing to Dock process from Activity Monitor.

Related:
myXprotect Status – a drop down list of threats protected against for the menu bar

Finder’s Nasty Inherited ACL Bug (aka Error -41)

Finder’s Inherited ACL handling is broken

Support for inherited ACLs on folders is still in disarray in 10.6.7 (and has been since 10.6.5), there have been a few reports here and there, some mentioning Error -41, other saying it was AFP, but I’ve whittled it down and it’s a Finder flaw handling inherited ACLs that was introduced in 10.6.3!

Hands On Demo

Let’s create a folder in your home directory using Terminal to make a nice little nested folder set to play with :
mkdir -p ~/ACLShackles/1/2/3/4/5/6/7/8/9/10/11

Now let’s add an entry to the folder’s ACL, in this case  inherited folder and file Read & Write permissions, a common setup for workgroups that share a folder. OS X’s Server Admin sets inheritance by default when adding a user to an ACL, to do this with OS X Client you must use chmod:

chmod +a "$(whoami) allow list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,directory_inherit" ~/ACLShackles/

Make sure the above is all on one line and paste into Terminal.
Now, that the permissions are set double check with: ls -led ~/ACLShackles

Now duplicate folder structure we made called “1” with Command-D, now try and duplicate “1 copy”  — it fails. Finder Error -41.

Looking at the ACL in Terminal isn’t pretty:
ls -leR /Users/brunerj/ACLShackles/1\ copy\ 2

It goes on to 108…

If you don’t like Terminal, I’ve got an Applescript for you: Error41.zip

Just download and, open the resulting Error41.dmg, open and run Error41.scpt to get this result:

Step-by-step illustrated Demo

Let’s try another example and illustrate.

Now, let’s copy in Chess.app, take a look at the permissions with the Inspector (Command-Option-I), notice the Permissions (for this example I added a different user in the ACL to avoid confusion between the Unix permission and the ACL when looking at Finder’s Get Info, it’s the same silhouette):

Looks good, and how it should. Now duplicate Chess.app within this folder with a Command-D:

Uh-oh. Something’s not right. It’s duplicated the original ACE (Access Control Entry) and added one for me the duplicator that seems to mimic my Unix permissions.

Copy the copy.

Much worse. It’s now duplicating my erroneous ACE and the ACE of the test user as well.

Copy the copy.

Oh dear. Fail. Error -41. Checkmate.

Let’s look at that third failed and truncated copy in Finder

Care to see how long an ACL is inside the app?

Yes. 110 ACEs are on “Chess copy 3.app/Contents”!

Comparing other file manager’s behavior

cp doesn’t suffer the same fate as Finder when making copies of copies.

This simulates Finder’s copy of a copy, delete any existing duplicate folders and try this:

cp -Rp 1 1\ copy; cp -Rp 1\ copy 1\ copy\ 2; cp -Rp 1\ copy\ 2 1\ copy\ 3; cp -Rp 1\ copy\ 3 1\ copy\ 4

Take a look inside with ls -leR ~/ACLShackles, nice and clean, one ACE per ACL on each folder the way it should be.

Rixstep’s XFile – doesn’t exhibit this behavior when copying or duplicating either, Rixstep software is quite conscientious about doing the Right Thing™

Path Finder however duplicates ACLs just like Finder, but instead of Error -41 when an ACL gets too long and deep it just hangs instead. What’s interesting is what calls is PathFinder using? They have an SDK but have only taken a cursory look, regardless it’s the same result as Finder.

In conclusion…

For OS X Server environments, this affects crucial workflow behavior where multiple people act upon the same files and folders. ACLs quickly stack up and render Finder unusable. Currently the last known proper behavior for Finder was 10.6.2. Then 10.6.3 and 10.6.4, added the quirk of  adding an ACL entry that mimicked the UNIX permissions of the user doing the copy operation, but at least the ACEs weren’t duplicated ad nauseum. But taking the insanity to new heights was 10.6.5, 10.6.6, and now 10.6.7 with the duplication bug that makes working with inherited permissions unbearable. Luckily for OS X Client, this is minimized since Finder does not enable Inheritance for files or folders, but then you lose out on what inherited ACLs could do for you and your workgroup!

Since 10.6.7 is out now, 10.6.8 might be your last chance to have Snow Leopard’s Finder ACL behavior put back in working order. Let Apple know this is important to you, file a bug report at Apple’s Bug Reporter site, you can reference my bug number: 9160099 (you can view it at OpenRadar )

P.S. If you are wondering why I didn’t file this earlier since I am so detailed in the earlier 10.6 behavior? I actually became aware of something wrong in 10.6.5 but I also wasn’t sure what the cause was, Client, Server, AFP, Active Direcroty? Our UIDs are 10 digits long! During that time I hoped the soon to be released 10.6.6 would fix it, but when it didn’t I spent a lot of time just trying to fix it and clean the ACLs, it wasn’t until last week during the final seed of 10.6.7 that I found time to set up a new server and incrementally test 10.6, 10.6.2, 10.6.3, 10.6.4, 10.6.5, 10.6.6, and 10.6.7, recording QT Screen captures for each one and that took some time! My bug report only got in this Sunday. Oh well better late than never! :/

Remedies

It’s easy to nuke all the ACLs in a given folder, but then you’ll probably want them set back up again to be of any use! Anyway this will recursively wipe the ACLs from everything in the folder you’re in, be careful, you could wipe your own access! So it’s best for the server admin to to run from the server itself, then re-propagate the ACLs for the Share (actually you may not be able to delete ACLs from client anyway):

chmod -RN *

Update (3/23/11):

So I left my ACLShackles folder in my home foder and Time Machine failed to backup (backupd error -41, surprise.) so to avoid that, delete ACLShackles and/or turn off Time Machine while you play around with this…

Update (Sep 2011):
Just posting my comment down at the bottom so you don’t have to scroll all the way down there to read it…

10.6.8 has addressed it for the most part. You’ll still get weirdness when duplicating folders with inherited folders inside a folder with inherited permissions, but it’s a linear rather than geometric and that’s bearable.