How to fix |mkfifo()| failure if |pathname| is on NFS ? / was: Re: [EXTERNAL] Re: mkfifo: cannot set permissions of 'x.fifo': Not a directory

Roland Mainz
Tue Aug 22 23:05:36 GMT 2023

On Tue, Aug 22, 2023 at 4:52 PM Lavrentiev, Anton (NIH/NLM/NCBI) [C]
via Cygwin <> wrote:
> > FIFOs which don't make *any* sense
> > ... FWIW, a remote NFS fileystem.
> I got an impression that the OP is trying to deploy something (maybe the entire Cygwin) onto an
> NFS share.  So the named FIFO "file" is also created in there.

I agree with that impression. This is basically what large sites
(universities etc) do with UNIX and Linux: The machines mount an
user's ${HOMR} directory via automounter over NFS, and users are
discouraged (e.g. grumpy admin visiting you in person, blocking all
escape routes... =:-) ) from using the machine's local filesystems (in
Cygwin's case that includes "C:"!).

In that case people want to use |mkfifo()|/|mkfifoat()| and/or
/usr/bin/mkfifo in their home directory, and don't expect that it does
not work.

But that is what happens on Cygwin 3.4.8 right now, if someone tries
to do a |mkfifo()| on a NFS home directory (tested with MS NFSv3 and
CITI NFSv4 clients):
|mkfifo()| succeeds, but the resulting inode is *NOT* a FIFO as requested

Example (/cygdrive/h/ is my home directory shared from my Linux machine):
---- snip ----
roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ uname -a
CYGWIN_NT-10.0-19045 winkrakra1 3.4.8-1.x86_64 2023-08-17 17:02 UTC
x86_64 Cygwin

roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ mount
C:/cygwin64/bin on /usr/bin type ntfs (binary,auto)
C:/cygwin64/lib on /usr/lib type ntfs (binary,auto)
C:/cygwin64 on / type ntfs (binary,auto)
C: on /cygdrive/c type ntfs (binary,posix=0,user,noumount,auto)
H: on /cygdrive/h type nfs (binary,posix=0,user,noumount,auto)

roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ ls -l
total 1
-rw-rw-rw- 1 Unix_User+0 Unix_Group+0 330 Aug 22 23:58 cygwin_mkfifo_on_nfs.c

roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ cat -n cygwin_mkfifo_on_nfs.c
     1  #include <stdlib.h>
     2  #include <stdio.h>
     3  #include <stdio.h>
     4  #include <errno.h>
     5  #include <sys/types.h>
     6  #include <sys/stat.h>
     8  int main(int ac, char *av[])
     9  {
    10          (void)puts("# start");
    12          if
(mkfifo("/cygdrive/h/work/cygwin_mkfifo_on_nfs/myfifo.fifo", 0) != 0)
    13                  perror("mkfifo failed");
    14          (void)puts("# done.");
    15          return EXIT_SUCCESS;
    16  }

roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ gcc -g cygwin_mkfifo_on_nfs.c

roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ ./a
# start
# done.

roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ ls -l
total 68
-rwxr-xr-x 1 Unix_User+0 Unix_Group+0 66951 Aug 23 00:12 a.exe
-rw-rw-rw- 1 Unix_User+0 Unix_Group+0   330 Aug 22 23:58 cygwin_mkfifo_on_nfs.c
lrwxrwxrwx 1 Unix_User+0 Unix_Group+0    11 Aug 23 00:12 myfifo.fifo
-> ':\0:c4:1000'

roland_mainz@winkrakra1 /cygdrive/h/work/cygwin_mkfifo_on_nfs
$ cat <myfifo.fifo
-bash: myfifo.fifo: No such file or directory
---- snip ----

Note that Cygwin does not interpret the file |myfifo.fifo| as FIFO,
instead it comes back as a symlink "myfifo.fifo -> ':\0:c4:1000'".

AFAIK there are (at least) these two options to fix the problems:
1. Check whether the filesystem for the fifos path is NFS
(cgywin.dll's |fs.fs_is_nfs()|), and if it is a symlink check if it
starts with ':\0:c4:' (assuming "c4" is the prefix for inodes created
with |mkfifo()|). If this condition is |true|, then cygwin |stat()|,
|open()| etc. should treat this inode as FIFO.
2. Check whether the filesystem for the fifos path is NFS
(cgywin.dll's |fs.fs_is_nfs()|), and then just refuse |mkfifo()| with
|ENOSYS| (not implemented)

Better algorithm for [1] might be to check whether the inode is a
symlink, and then do a |fs.fs_is_nfs()| on the symlinks |pathname|,
assuming this is more performant.

> It's pointless to assume that the FIFO can be used as a communication
> device between the hosts that can mount the share, but it can be quite
> feasible to envision a scenario, in which the same host opens the FIFO
> located on the share from two processes and establish the
> communication using that special "file" (which is basically a special
> data-less i-node).

Well, this is what RFS (see was doing - but it
was removed in Solaris 2.4, because its complexity was too great
(well, the original implementation was simple and clean, and then it
grew all over the kernel just to handle all corner cases of POSIX&co.)
- and it would be nice not to repeat the mistakes of the past.


  __ .  . __
 (o.\ \/ /.o)
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 3992797
 (;O/ \/ \O;)

More information about the Cygwin mailing list