public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: Houder <houder@xs4all.nl>
To: cygwin@cygwin.com
Subject: Re: /dev/fd/N not synonymous with file descriptor N; it is on Linux
Date: Tue, 22 Jan 2019 08:57:00 -0000	[thread overview]
Message-ID: <1c60402837d6510667357257b5e96e88@xs4all.nl> (raw)
In-Reply-To: <d6431739e2801a80d73e7cb68b4fcc19@smtp-cloud8.xs4all.net>

[-- Attachment #1: Type: text/plain, Size: 1212 bytes --]

On 2019-01-22 09:50, Houder wrote:
> On Sun, 6 Jan 2019 21:19:50, Corinna Vinschen  wrote:
>> 
>> On Dec 16 17:31, Houder wrote:
>> > 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 should work in the latest developer snapshot uploaded to
>> https://cygwin.com/snapshots/  Please give it a try.
>> 
>> Thanks,
>> Corinna
> 
> Nice!
> 
> This solves: <program> -i /dev/fd/N N<<EOF (i.e. Steven Penny's 
> problem)
> 
> Howver ...
> (and I sure that I am not telling you anything new)
> 
> it still not the same as Linux ...
> 
> So, for the record only:

and as another example, this STC succeeds on Linux ..., but fails on 
Cygwin.

64-@@ ./stca /dev/fd/0 <<EOF
> bla
> EOF
fd1 = 0
argv[1] = /dev/fd/0
fd2 = 3
id = writefd2, errno = 13, errstr = Permission denied
64-@@

=====


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: stca.c --]
[-- Type: text/x-c; name=stca.c, Size: 6104 bytes --]

// gcc -Wall -o stca stca.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h> // strerror()
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h> // lstat()
#include <time.h>

/*
 A file that has been deleted, but is still "held open" by an entry in the open file table
 (i.e. the file is referred by an open file descriptor), can be opened again read-write in
 Linux, but not in Cygwin ...
 */

// NOTE: my text uses "fd 2" for a file descriptor that equals 2; and fd2 for variable fd2

static int
errExit(const char *str)
{
    printf("id = %s, errno = %d, errstr = %s\n", str, errno, strerror(errno));
    fflush(stdout);
    exit(EXIT_FAILURE);
}

static void
Usage(const char *const arg)
{
    fprintf(stderr, "Usage: %s /dev/fd/N\n", arg);
    exit(EXIT_FAILURE);
}

#if 0
#define DISPLAYSTATINFO
static void displayStatInfo(const struct stat *sb);
#endif

// invoke as follows: ./stca /dev/fd/0 <<EOF

int
main(int argc, char *argv[])
{
    if (argc < 2) {
        Usage(argv[0]);
        exit(EXIT_SUCCESS);
    }

    // @@ ./stca /dev/fd/8 8<<EOF 0<&- # fd 8 is connected to tmpfile (bash!)
    // using an argument, the stc can be told to read from fd 8 (fd 0 can be closed)
    // @@ ./stca /dev/fd/5 8<<EOF 5<&8- 0<&- # ... here fd 0 and fd 8 are closed

    // kludge
    if (strlen(argv[1]) < 9) Usage(argv[0]);
    if (strncmp(argv[1], "/dev/fd/", 8) != 0) Usage(argv[0]);
    if ( (strlen(argv[1]) > 9) ||
         ( (argv[1][8] - 0x30 < 0) || (argv[1][8] - 0x30 > 9) ) ) {
        fprintf(stderr, "N must be a single digit, please!\n");
        Usage(argv[0]);
    }
    // end kludge

    int fd1;
    fd1 = argv[1][8] - 0x30;
    printf("fd1 = %d\n", fd1);

    // using bash, /dev/fd/N refers to a file which been unlink'ed
    printf("argv[1] = %s\n", argv[1]);

    errno = 0;

    int fd2;
#if 0
    if ( (fd2 = open(argv[1], O_RDONLY)) == -1) errExit("openfd2"); // what 'cat' does
#else
#define WRITE
    if ( (fd2 = open(argv[1], O_RDWR)) == -1) errExit("openfd2");
    //if ( (fd2 = open(argv[1], O_RDWR | O_APPEND)) == -1) errExit("openfd2");
#endif
    printf("fd2 = %d\n", fd2);

#if defined(DISPLAYSTATINFO)
    struct stat sb;
    if (fstat(fd2, &sb) == -1) errExit("fstatfd2");
    displayStatInfo(&sb);
#endif

    /* if file has been opened read-write, write() will succeed in Linux,
       but fail in Cygwin
     */

#if defined(WRITE)
    if (write(fd2, "Hello, world!\n", 14) == -1) errExit("writefd2");
#endif

    // how about an lseek() first? (write() modifies the file offset)
    if (lseek(fd2, 0, SEEK_SET) == -1) errExit("lseekfd2");

    char buf[80] = { 0 }; // another kludge
    if (read(fd2, buf, sizeof(buf) ) == -1) errExit("readfd2");
    printf("buf = \\\n%s", buf);

    if (close(fd2) == -1) printf("closefd2 failed\n");
}

#if defined(DISPLAYSTATINFO)
  #if 1
static void
displayStatInfo(const struct stat *sb)
{
   printf("Link count: %ld\n", (long)sb->st_nlink);
}

  #else
static char *filePermStr(mode_t perm, int flags);

static void
displayStatInfo(const struct stat *sb)
{
   printf("File type:                ");

   // deprecated by S_ISREG(m) and c.s. ...? /usr/include/linux/stat.h
   switch (sb->st_mode & S_IFMT) {
   case S_IFBLK:  printf("block device\n");            break;
   case S_IFCHR:  printf("character device\n");        break;
   case S_IFDIR:  printf("directory\n");               break;
   case S_IFIFO:  printf("FIFO/pipe\n");               break;
   case S_IFLNK:  printf("symlink\n");                 break;
   case S_IFREG:  printf("regular file\n");            break;
   case S_IFSOCK: printf("socket\n");                  break;
   default:       printf("unknown?\n");                break;
   }

   printf("I-node number:            %ld\n", (long)sb->st_ino);

#if 0
   printf("Mode:                     %lo (octal)\n", (unsigned long)sb->st_mode);
#else
   printf("Mode:                     %lo (octal), ls(1)-style: %s\n",
                                     (unsigned long)sb->st_mode, filePermStr(sb->st_mode, 0));
#endif

   printf("Link count:               %ld\n", (long)sb->st_nlink);
   printf("Ownership:                UID=%ld   GID=%ld\n", (long)sb->st_uid, (long)sb->st_gid);

   printf("Preferred I/O block size: %ld bytes\n", (long)sb->st_blksize);
   printf("File size:                %lld bytes\n", (long long)sb->st_size);
   printf("Blocks allocated:         %lld\n", (long long)sb->st_blocks);

   printf("Last status change:       %s", ctime(&sb->st_ctime));
   printf("Last file access:         %s", ctime(&sb->st_atime));
   printf("Last file modification:   %s", ctime(&sb->st_mtime));
}

/* Return ls(1)-style string for file permissions mask */

/* Include set-user-ID, set-group-ID, and sticky bit information in
   returned string */
#define FP_SPECIAL 1

#define STR_SIZE sizeof("rwxrwxrwx")

static char *
filePermStr(mode_t perm, int flags)
{
    static char str[STR_SIZE];

    /* If FP_SPECIAL was specified, we emulate the trickery of ls(1) in
       returning set-user-ID, set-group-ID, and sticky bit information in
       the user/group/other execute fields. This is made more complex by
       the fact that the case of the character displayed for this bits
       depends on whether the corresponding execute bit is on or off. */

    snprintf(str, STR_SIZE, "%c%c%c%c%c%c%c%c%c",
        (perm & S_IRUSR) ? 'r' : '-', (perm & S_IWUSR) ? 'w' : '-',
        (perm & S_IXUSR) ?
            (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 's' : 'x') :
            (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 'S' : '-'),
        (perm & S_IRGRP) ? 'r' : '-', (perm & S_IWGRP) ? 'w' : '-',
        (perm & S_IXGRP) ?
            (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 's' : 'x') :
            (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 'S' : '-'),
        (perm & S_IROTH) ? 'r' : '-', (perm & S_IWOTH) ? 'w' : '-',
        (perm & S_IXOTH) ?
            (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 't' : 'x') :
            (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 'T' : '-'));

    return str;
}
  #endif
#endif

//=====

[-- Attachment #3: Type: text/plain, Size: 219 bytes --]


--
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

  reply	other threads:[~2019-01-22  8:57 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-16 16:31 Houder
2018-12-16 20:28 ` Corinna Vinschen
2018-12-16 20:31   ` Corinna Vinschen
2018-12-16 21:36   ` Wayne Davison
2018-12-16 21:55     ` Corinna Vinschen
2018-12-17  4:30       ` Houder
2018-12-17  9:25         ` Corinna Vinschen
2018-12-17 11:26           ` Corinna Vinschen
2019-01-02 13:56             ` Houder
2018-12-17  3:41   ` Houder
2019-01-06 20:19 ` Corinna Vinschen
2019-01-22  8:50   ` Houder
2019-01-22  8:57     ` Houder [this message]
2019-01-22  9:06       ` Corinna Vinschen
2019-01-22  9:25         ` Houder
2019-01-22  9:42           ` Corinna Vinschen
2019-01-22 10:20             ` Houder
2019-01-22 10:39               ` Corinna Vinschen
2019-01-27 18:39                 ` Houder
2019-01-27 21:57                   ` Corinna Vinschen
2019-01-27 22:12                     ` Corinna Vinschen
2019-01-28 14:15                     ` Houder
2019-01-28 16:51                       ` Corinna Vinschen
2019-01-22  9:02     ` Corinna Vinschen
2019-01-22  9:07       ` Corinna Vinschen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1c60402837d6510667357257b5e96e88@xs4all.nl \
    --to=houder@xs4all.nl \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).