]> granicus.if.org Git - postgresql/commitdiff
Fix pg_recvlogical not to fsync output when it's a tty or pipe.
authorAndres Freund <andres@anarazel.de>
Tue, 7 Jul 2015 10:47:44 +0000 (12:47 +0200)
committerAndres Freund <andres@anarazel.de>
Tue, 7 Jul 2015 10:54:11 +0000 (12:54 +0200)
The previous coding tried to handle possible failures when fsyncing a
tty or pipe fd by accepting EINVAL - but apparently some
platforms (windows, OSX) don't reliably return that. So instead check
whether the output fd refers to a pipe or a tty when opening it.

Reported-By: Olivier Gosseaume, Marko Tiikkaja
Discussion: 559AF98B.3050901@joh.to

Backpatch to 9.4, where pg_recvlogical was added.

src/bin/pg_basebackup/pg_recvlogical.c

index 0bc141dd79bc0e4be391a8df9cce63a136232a68..50844e700d9604d0014fac5e346bbdd5a7204f8e 100644 (file)
@@ -50,6 +50,7 @@ static const char *plugin = "test_decoding";
 static int     outfd = -1;
 static volatile sig_atomic_t time_to_abort = false;
 static volatile sig_atomic_t output_reopen = false;
+static bool output_isfile;
 static int64 output_last_fsync = -1;
 static bool output_needs_fsync = false;
 static XLogRecPtr output_written_lsn = InvalidXLogRecPtr;
@@ -177,8 +178,11 @@ OutputFsync(int64 now)
 
        output_needs_fsync = false;
 
-       /* Accept EINVAL, in case output is writing to a pipe or similar. */
-       if (fsync(outfd) != 0 && errno != EINVAL)
+       /* can only fsync if it's a regular file */
+       if (!output_isfile)
+               return true;
+
+       if (fsync(outfd) != 0)
        {
                fprintf(stderr,
                                _("%s: could not fsync log file \"%s\": %s\n"),
@@ -317,6 +321,8 @@ StreamLogicalLog(void)
                /* open the output file, if not open yet */
                if (outfd == -1)
                {
+                       struct stat statbuf;
+
                        if (strcmp(outfile, "-") == 0)
                                outfd = fileno(stdout);
                        else
@@ -329,6 +335,13 @@ StreamLogicalLog(void)
                                                progname, outfile, strerror(errno));
                                goto error;
                        }
+
+                       if (fstat(outfd, &statbuf) != 0)
+                               fprintf(stderr,
+                                               _("%s: could not stat file \"%s\": %s\n"),
+                                               progname, outfile, strerror(errno));
+
+                       output_isfile = S_ISREG(statbuf.st_mode) && !isatty(outfd);
                }
 
                r = PQgetCopyData(conn, &copybuf, 1);