Subject: Re: [bug] install(1) fails to read /dev/stdin on Darwin

From: Sergei Trofimovich <[email-masked]>
Date: Thu, 18 Apr 2024 22:52:32 +0100

On Tue, 16 Apr 2024 22:37:58 +0100
Sergei Trofimovich <[email-masked]> wrote:

> On Tue, 16 Apr 2024 12:33:44 +0100
> Pádraig Brady <[email-masked]> wrote:
> 
> > On 16/04/2024 01:19, Alejandro Colomar wrote:  
> > > Hi!
> > > 
> > > I don't own a Darwin system, so I can't help much reproduce.  However,
> > > I've received a bug report to the Linux man-pages, that our build
> > > system (GNUmakefile-based), which ends up calling
> > > 
> > > 	... | install /dev/stdin $@
> > > 
> > > doesn't work on Darwin.  Here's the original bug report:
> > > <https://github.com/NixOS/nixpkgs/pull/300797>.
> > > 
> > > Here are the reported error messages:
> > > 
> > > ...
> > > INSTALL         /nix/store/3s28l9ijlkmsq8256zdxjvl173gkn37c-man-pages-6.7/share/man/man3/addseverity.3
> > > INSTALL         /nix/store/3s28l9ijlkmsq8256zdxjvl173gkn37c-man-pages-6.7/share/man/man3/adjtime.3
> > > install: skipping file '/dev/stdin', as it was replaced while being copied
> > > make: *** [share/mk/install/man.mk:54: /nix/store/3s28l9ijlkmsq8256zdxjvl173gkn37c-man-pages-6.7/share/man/man3/addmntent.3] Error 1
> > > make: *** Waiting for unfinished jobs....
> > > install: skipping file '/dev/stdin', as it was replaced while being copied
> > > make: *** [share/mk/install/man.mk:54: /nix/store/3s28l9ijlkmsq8256zdxjvl173gkn37c-man-pages-6.7/share/man/man3/acosh.3] Error 1
> > > install: skipping file '/dev/stdin', as it was replaced while being copied
> > > install: skipping file '/dev/stdin', as it was replaced while being copied
> > > install: skipping file '/dev/stdin', as it was replaced while being copied
> > > ...
> > > 
> > > I don't see why install(1) should fail to read /dev/stdin under any
> > > POSIX system    
> > 
> > What version of darwin is this? I can't repro on Darwin 21.6.0 (MacOSX 12.6).
> > The issue seems to be that /dev/stdin returns a varying inode which install(1) doesn't like currently  
> 
> The system I have locally is this one:
> 
>     $ uname -a
>     Darwin tests-iMac.local 18.7.0 Darwin Kernel Version 18.7.0: Tue Jun 22 19:37:08 PDT 2021; root:xnu-4903.278.70~1/RELEASE_X86_64 x86_64

I debugged it a bit more locally and it looks like it's a known
limitation of fstat()/stat() mismatch on FIFOs on Darwin. Example
program:

$ cat simple.c
#include <sys/stat.h>
#include <assert.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
      struct stat s;
      int fd;
      int r;

      fd = open("/dev/fd/0", O_RDONLY);
      assert(fd > 0);
      r = fstat(fd, &s);
      assert(r == 0);
      fprintf(stderr, "1: ino=%llu\n", s.st_ino);
      close(fd);

      fd = open("/dev/fd/0", O_RDONLY);
      assert(fd > 0);
      r = fstat(fd, &s);
      assert(r == 0);
      fprintf(stderr, "2: ino=%llu\n", s.st_ino);
      close(fd);

      r = stat("/dev/fd/0", &s);
      assert(r == 0);
      fprintf(stderr, "3: ino=%llu\n", s.st_ino);
      close(fd);
}

Running:

$ clang simple.c -o simple && echo 42 | ./simple
1: ino=3009428657538693161
2: ino=3009428657538693161
3: ino=1568241705

Note how stat() and fstat() don't agree on inode.

Apparently it's documented in
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fstat.2.html
as

  BUGS
     Applying fstat to a socket (and thus to a pipe) returns a zero'd buffer,
     except for the blocksize field, and a unique device and inode number.

Perhaps coreutils should avoid inode checks on FIFOs and sockets. They
are already volatile by nature.

-- 

  Sergei