// gcc -Wall -o stc stc.c #include #include #include #include // strerror() #include #include /* 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"); } //=====