/* * /dev/stdout test program. * * This is to be run with one argument, that argument being one of the * five strings same, wdw, dww, wow, or oww. In each case, it does * two write()s, the first writing STR1 length LEN1, the second * writing STR2 length LEN2. The first write is always to standard * output, file descriptor 1; they differ in where the second * descriptor comes from: * * Arg Second descriptor is... * same Also fd 1. * wdw dup(1), done between the write()s. * dww dup(1), done before either write(). * wow open(/dev/stdout), done between the write()s. * oww open(/dev/stdout), done before either write(). * * The three-letter names are abbreviations for "write, dup, write" or * "open, write, write", or the like. The open on /dev/stdout uses * O_WRONLY|O_CREAT|O_TRUNC, like typical shell redirection. * * My test systems are NetBSD (a 1.4T derivative) and Ubuntu 16.04.1 * LTS. On NetBSD, or on the Ubuntu if stdout is a tty or a pipe (or, * I suspect, anything else unseekable) everything works fine: all * five options give the same output: * * This is write #1 * Write #2 * * But, when stdout is redirected to a file, wow and oww differ: I see * oww giving * * Write #2 * rite #1 * * and wow giving * * Write #2 * * It looks to me as though Linux - or at least Ubuntu - /dev/stdout * creates a new open file table entry on the same underlying object * (as opposed to dup(), which creates a new file descriptor on the * same open file table entry). I'm having trouble finding a weaker * word for this than "broken"; it most certainly violates POLA, at * least for me. */ #include #include #include #include #include #include extern const char *__progname; #define STR1 "This is write #1\n" #define LEN1 17 #define STR2 "Write #2\n" #define LEN2 9 #define DEV_STDOUT "/dev/stdout" static void usage(void) { fprintf(stderr,"Usage: %s same|wdw|dww|wow|oww\n",__progname); exit(1); } static int open_dev_stdout(void) { int d; d = open(DEV_STDOUT,O_WRONLY|O_CREAT|O_TRUNC,0666); if (d < 0) { fprintf(stderr,"%s: open %s: %s\n",__progname,DEV_STDOUT,strerror(errno)); exit(1); } return(d); } static void test_same(void) { write(1,STR1,LEN1); write(1,STR2,LEN2); } static void test_wdw(void) { int d; write(1,STR1,LEN1); d = dup(1); write(d,STR2,LEN2); } static void test_dww(void) { int d; d = dup(1); write(1,STR1,LEN1); write(d,STR2,LEN2); } static void test_oww(void) { int d; d = open_dev_stdout(); write(1,STR1,LEN1); write(d,STR2,LEN2); } static void test_wow(void) { int d; write(1,STR1,LEN1); d = open_dev_stdout(); write(d,STR2,LEN2); } int main(int, char **); int main(int ac, char **av) { if (ac < 2) usage(); #define FOO(x) do { if (!strcmp(av[1],#x)) { test_##x(); return(0); } } while (0) FOO(same); FOO(wdw); FOO(dww); FOO(wow); FOO(oww); usage(); return(1); }