Being neither a C programmer nor a Texinfo fan, checking GNU RCS is a bit painful, and my conclusions aren't guaranteed.

AFAICT, GNU RCS (v5.9.4, ca. 2015, examined) creates a temp file, unlinks the target file, then renames the temp file. I beleve this guarantees(-ish, modulo "special" filesystems including NFS and FreeBSD's directory-SUID behaviour) that resulting file ownership = euid.

The GNU docs mention the repo owner in passing a few times but do not have a section describing multi-user operation.

The Tichy docs also don't mention file ownership. I'm trying to review the O'Donovan book, too, but it's been a long time since I had to tool up to handle raw PS... not quite there yet.

Purdue RCS appears to be the direct ancestor of GNU RCS.

I'm not sure which other implementations you'd be worried about - I thought OpenBSD's RCS was the direct descendant of NetBSD's and shares common lineage with the other *BSDs?

All in all, it looks like RCS and its docs were written in the era when UNIX machines were - more or less by universally - used by multiple people, and you just had an innate sense of how multi-user file ownership would work. Most of my UNIX machines now resemble appliances, and exactly zero of them are multi-user in the classical sense.

-Adam


On 2020-04-29 21:53, Theo de Raadt wrote:
Sorry, but my mail goes further.

It says it should be correct.  For some definition of correct.  It
should either behave somehow for a logical reason, or it should behave
in the historical fashion.  Or once the historical behaviour is looked
at, if there is an argument that is wrong, then it should be changed
with logic about "this is an improvement" backing the argument.

I think it is wrong to document how *this* rcs implimentation behaves,
without comparing it against others.

My guess is 50% that the others don't unlink, but rewrite the file.

And the changes it might require to be compatible are not substantial.
At most a 20 line diff, to a few programs in the family.

athom...@athompso.net wrote:

Thank you for that detail!

Addressing this one corner case would require substantial changes, I think. Not worth
it, in my opinion.

I think it would be worthwhile describing the multi-user mode of operation of RCS in the manual, as it's currently completely absent/omitted. Patch coming soon, maybe
tomorrow if I can make time.

-Adam

On Apr. 29, 2020 21:28, Theo de Raadt <dera...@openbsd.org> wrote:

 athom...@athompso.net wrote:

> Heh, good point. Didn't even occur to me because as it happens, I am
 > running as root and would like to not change the ownership.-Adam
> On Apr. 29, 2020 13:32, Anders Andersson <pipat...@gmail.com> wrote:
 >
> On Wed, Apr 29, 2020 at 7:46 PM Adam Thompson <athom...@athompso.net>
 >   wrote:
 >   >
> > When I use co(1) with "-l" to check out a file (and/or "ci -l") is
 >   there
> > any way to preserve file ownership and *not* have it reset to the
 >   user
 >   > running co(1) or ci(1)?
> > I don't see anything in rcs(1), co(1) or ci(1) that even mentions
 >   the
 >   > fact that the file will wind up owned by the user running the
 >   command.
 >   > Ideas?  Pointers to documentation?
 >
> How could it possibly do anything else unless you always run co as
 >   root?

 Our rcs tools do:

 52628 co       RET   kbind 0
 52628 co       CALL  unlink(0x7f7ffffed1f3)
 52628 co       NAMI  "ls.c"
 52628 co       RET   unlink -1 errno 2 No such file or directory
 52628 co       CALL  open
 (0x7f7ffffed1f3,0x601<O_WRONLY|O_CREAT|O_TRUNC>,0100444<S_IRUSR\
 |S_IRGRP|S_IROTH|S_IFREG>)
 52628 co       NAMI  "ls.c"
 52628 co       RET   open 4
 52628 co       CALL  kbind(0x7f7ffffec908,24,0x847da2a816b5d817)

 Which appears to be this:

         else {
                 (void)unlink(dst);

if ((fd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1)
                         err(1, "%s", dst);

I don't know what older or gnu rcs do. I guess whichever way this is done it must balance concerns between atomicity of concurrent reads performed by earlier processes, versus replacement of a potentially active file.

 If the latter is chosen, it would unlink(), perform the open more
 carefully, check that it is in the right place with fstat, but then
 it needs some work for ftruncate (to get rid of extra file contents
at the end). If the open() failed, it might try an unlink followed by
 open()?

Other rcs implimentations need to be checked. It is better if they work
 the same.


Reply via email to