This is the mail archive of the
cygwin
mailing list for the Cygwin project.
/dev/fd/N not synonymous with file descriptor N; it is on Linux
- From: Houder <houder at xs4all dot nl>
- To: cygwin at cygwin dot com
- Date: Sun, 16 Dec 2018 17:31:32 +0100
- Subject: /dev/fd/N not synonymous with file descriptor N; it is on Linux
L.S.,
/dev/fd/N not synonymous with file descriptor N; it is on Linux
64-@@ cat /dev/fd/0 <<\EOF
Hi
EOF
cat: /dev/fd/0: No such file or directory
fails on Cygwin; not on Linux.
Also see:
https://cygwin.com/ml/cygwin/2018-12/msg00028.html
( Bash heredoc on FD 3 )
Based on the output of strace on Linux, I composed an STC, that
duplicates
the steps taken by bash (and cat).
This STC succeeds on Linux, but fails on Cygwin.
What does the STC do:
- it creates a (temporary) file in the same way that bash does
- the file is written to, the file descriptor is closed and the file
unlinked
- however, before the file is unlinked, it is opened a second time,
like bash
would do
Next
- the file /dev/fd/N is opened, where N is the file descriptor that has
been
left open; this is what the "cat command" would do.
The "cat command" on Linux succeeds; it fails on Cygwin.
Regards,
Henri
STC attached (hopefully)
=====
// gcc -Wall -o stc stc.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h> // strerror()
#include <errno.h>
#include <fcntl.h>
/*
LPI, 5.11 The /dev/fd Directory (Linux Programming Interface, Michael Kerrisk)
"For each process, the kernel provides the special virtual directory /dev/fd.
This directory contains filenames of the form /dev/fd/n, where n is a number
corresponding to one of the open file descriptors for the process."
"... Opening one of the files in the /dev/fd directory is equivalent to duplicating
the corresponding file descriptor. ..."
"... The files in the /dev/fd directory are rarely used within programs. Their most
common use is in the shell. Many user-level commands take filename arguments, and
sometimes we would like to put them in a pipeline and have one of the arguments be
standard input or output instead. ..."
*/
void
errExit(const char *str)
{
printf("id = %s, errno = %d, errstr = %s\n", str, errno, strerror(errno));
fflush(stdout);
exit(EXIT_FAILURE);
}
int
main()
{
int fd1, fd2, fd3;
errno = 0;
// create a tmpfile in the same way that bash would do ...
fd1 = open("/tmp/stc.txt", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
if (fd1 == -1)
errExit("openfd1");
errno = 0;
if (write(fd1, "Hello, world!\n", 14) == -1) errExit("writefd1");
errno = 0;
// also open this tmpfile for reading like bash would do ...
fd2 = open("/tmp/stc.txt", O_RDONLY);
if (fd2 == -1)
errExit("openfd2");
errno = 0;
// close fd 1 like bash would do ...
if (close(fd1) == -1) errExit("closefd1");
errno = 0;
// delete the tmpfile like bash would do ...
if (unlink("/tmp/stc.txt") == -1) errExit("unlink");
// kludge: compose a string (using fd2) representing "the device file"
// in /dev/fd (a symlnk to /proc/self/fd) for the file descriptor fd 2
// that is still open ...
char devfile[12] = "/dev/fd/"; devfile[8] = fd2 + 0x30; devfile[9] = '\0';
printf("devfile = %s\n", devfile);
errno = 0;
// open this device file; it succeeds on Linux, but fails on Cygwin ...
fd3 = open(devfile, O_RDONLY);
const char *id = "openfd3";
if (fd3 == -1) {
#if 0
errExit(id);
#else
printf("%s: Cannot open!, id = %s, errno = %d, errmsg = %s\n", devfile,
id, errno, strerror(errno));
char buf[16] = { 0 };
// however the file to which the symlnk refers, is still present ...
// Q: does Cygwin attempt to read the /tmp directory? (an attempt that
// will fail, because the file has been unlinked)
// it appears that a readlink of a file in /dev/fd must be diverted to
// the open file descriptor of the process ...
errno = 0;
if (read(fd2, buf, sizeof(buf) ) == -1) errExit("readfd2");
printf("buf = %s", buf);
if (close(fd2) == -1) printf("closefd2 failed\n");
exit(EXIT_FAILURE);
#endif
}
char buf[16] = { 0 };
errno = 0;
if (read(fd3, buf, sizeof(buf) ) == -1) errExit("readfd3");
printf("buf = %s", buf);
if (close(fd3) == -1) printf("closefd3 failed\n");
if (close(fd2) == -1) printf("closefd2 failed\n");
}
//=====
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple