More on chown in combination with symlinks

April 22, 2020

One of the things that writing Wandering Thoughts does is give me the opportunity to be inaccurate in public. Yesterday I wrote about how you should use '-h' with chown, especially for recursive chowns so that you don't change the ownership of things that symlinks point to. As it happens, I was mistaken about some aspects of the situation with chown.

First off, I stand by my overall recommendation that you should make a habit of always using 'chown -h'. Although using it with -R is probably not necessary after all (on any modern system), 'chown -h' remains the only way to safely chown all of the files in a directory with eg 'chown -h user *' or 'chown -h user *.html' or the like.

The situation with recursive chowns ('chown -R') is a little less obvious. First, as pointed out to me on Twitter, in reality modern versions of GNU chown do not change what symlinks point to with plain 'chown -R user dirtree'. Second, the POSIX standard for chown turns out to requires this behavior for 'chown -PR', so any version of chown that follows POSIX and has '-P' as the default mode for '-R' will behave this way even if its behavior isn't clear from its manpage. All of OpenBSD, FreeBSD, and Illumos default to '-P' this way. OpenBSD explicitly claims adherence to POSIX, FreeBSD is unclear but probably behaves sensibly, and the Illumos chown manpage explicitly and clearly describes '-P' as working like '-h'.

(It may be that my use of 'chown -hR' has always been somewhat of a superstition, for all that the GNU chown manpage uses it in an example.)

The bad news is that the clarity and explicitness of the Illumos chown manpage and the POSIX specification is uncommon; other people's documentation for chown will generally leave you puzzled and uncertain (or certain that they are actually dangerous). The documentation for GNU chown, FreeBSD chown, and OpenBSD chown all talk vaguely about 'traversing' or 'following' symlinks and are written in the context of descending through directory hierarchies. GNU chown even has a section of its full documentation which explicitly claims that '-P' is independent of '-h' and governs only directory traversal.

It is technically true that calling 'chown(2)' on a symbolic link causes the kernel to traverse or follow the symbolic link to change the ownership of the target, and so in a very legalistic robot logic way you could say that documenting '-P' to not 'traverse' or 'follow' symlinks implies that chown won't change the ownership of the target of symlinks. But I think very few people are going to read it that way (and for GNU chown, you are still left with the awkward fact that it explicitly rejects this interpretation).

All of this leads me to my overall recommendation that since all of this is confusing, you should always use 'chown -hR' on Unixes that support it, which is almost all of them except for OpenBSD.

(GNU chown is probably not POSIX compatible here in general, but that's a complicated issue.)

Sidebar: The explanation for GNU chown's behavior

It turns out that the installed GNU chown manpage is more terse than the official documentation and this terseness leads it to be inaccurate. The versions of the chown manpage I have access to say, about the '--dereference' option:

affect the referent of each symbolic link (this is the default), rather than the symbolic link itself

The real full documentation here says instead (in part):

Do not act on symbolic links themselves but rather on what they point to. This is the default when not operating recursively.

The second sentence implies that -h is the default when operating recursively, which reconciles the full documentation for -P with the observed behavior of plain 'chown -R'. You should still use 'chown -hR', though. After all, the chown manual itself does.

Comments on this page:

By Olivier at 2020-04-23 04:36:30:

I should not "always use 'chown -hR' on Unixes that support it", because that is not POSIX compliant (see the synopsis, these two options are not meant to be used simultaneously). According to the manuals 'chown -h' (without -R) and 'chown -R -P' do not follow any symlink. Also '-P' is the default after '-R' at least for GNU chown and OpenBSD chown, so if there is something to worry about it is non-recursive chown.

By cks at 2020-04-23 10:07:34:

I don't think POSIX is necessarily that restrictive. In general, POSIX doesn't forbid programs from taking additional options not required by POSIX; the POSIX options are the minimum requirements unless stated otherwise. The POSIX chown specification doesn't require 'chown -hR' to fail (it says nothing about the combination); it merely implicitly says that 'chown -R' is not required to accept -h, because it's not listed in the -R version of the chown Synopsis. A version of chown that accepts both at once, such as the FreeBSD one, is still POSIX compliant.

In practice, very few people and shell scripts restrict themselves to purely POSIX shell usage. Certainly in command line usage it's routine to go outside this, and there is only one reasonably common Unix where this doesn't work (OpenBSD).

As far as GNU chown goes, -P is irrelevant here because GNU chown explicitly documents that -P has non-POSIX behavior. Unlike what POSIX requires, -P, -H, and -L only affect directory traversal, not whether symlinks or symlink targets are chowned. The behavior of 'chown -PR' is POSIX compliant only because GNU chown makes -h the default behavior for recursive operation.

(As far as I know, the behavior of 'chown -HR' and 'chown -LR' is thus not POSIX compliant.)

Written on 22 April 2020.
« An important safety note about chown and symlinks (also chmod and chgrp)
The Unix divide over who gets to chown things, and (disk space) quotas »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Apr 22 01:08:13 2020
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.