diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index befb507047..1c17348472 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9067,8 +9067,10 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile) (errcode_for_file_access(), errmsg("could not create file \"%s\": %m", BACKUP_LABEL_FILE))); - fwrite(labelfbuf.data, labelfbuf.len, 1, fp); - if (fflush(fp) || ferror(fp) || FreeFile(fp)) + if (fwrite(labelfbuf.data, labelfbuf.len, 1, fp) != 1 || + fflush(fp) != 0 || + ferror(fp) || + FreeFile(fp)) ereport(ERROR, (errcode_for_file_access(), errmsg("could not write file \"%s\": %m", diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index a9c1980e5d..e0c72d9cdc 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -466,9 +466,9 @@ CopySendEndOfRow(CopyState cstate) #endif } - (void) fwrite(fe_msgbuf->data, fe_msgbuf->len, - 1, cstate->copy_file); - if (ferror(cstate->copy_file)) + if (fwrite(fe_msgbuf->data, fe_msgbuf->len, 1, + cstate->copy_file) != 1 || + ferror(cstate->copy_file)) ereport(ERROR, (errcode_for_file_access(), errmsg("could not write to COPY file: %m"))); diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 9132db7e81..44956c15b5 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -3284,6 +3284,7 @@ pgstat_write_statsfile(bool permanent) int32 format_id; const char *tmpfile = permanent ? PGSTAT_STAT_PERMANENT_TMPFILE : pgstat_stat_tmpname; const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename; + int rc; /* * Open the statistics temp file to write out the current values. @@ -3307,12 +3308,14 @@ pgstat_write_statsfile(bool permanent) * Write the file header --- currently just a format ID. */ format_id = PGSTAT_FILE_FORMAT_ID; - fwrite(&format_id, sizeof(format_id), 1, fpout); + rc = fwrite(&format_id, sizeof(format_id), 1, fpout); + (void) rc; /* we'll check for error with ferror */ /* * Write global stats struct */ - fwrite(&globalStats, sizeof(globalStats), 1, fpout); + rc = fwrite(&globalStats, sizeof(globalStats), 1, fpout); + (void) rc; /* we'll check for error with ferror */ /* * Walk through the database table. @@ -3326,7 +3329,8 @@ pgstat_write_statsfile(bool permanent) * use to any other process. */ fputc('D', fpout); - fwrite(dbentry, offsetof(PgStat_StatDBEntry, tables), 1, fpout); + rc = fwrite(dbentry, offsetof(PgStat_StatDBEntry, tables), 1, fpout); + (void) rc; /* we'll check for error with ferror */ /* * Walk through the database's access stats per table. @@ -3335,7 +3339,8 @@ pgstat_write_statsfile(bool permanent) while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&tstat)) != NULL) { fputc('T', fpout); - fwrite(tabentry, sizeof(PgStat_StatTabEntry), 1, fpout); + rc = fwrite(tabentry, sizeof(PgStat_StatTabEntry), 1, fpout); + (void) rc; /* we'll check for error with ferror */ } /* @@ -3345,7 +3350,8 @@ pgstat_write_statsfile(bool permanent) while ((funcentry = (PgStat_StatFuncEntry *) hash_seq_search(&fstat)) != NULL) { fputc('F', fpout); - fwrite(funcentry, sizeof(PgStat_StatFuncEntry), 1, fpout); + rc = fwrite(funcentry, sizeof(PgStat_StatFuncEntry), 1, fpout); + (void) rc; /* we'll check for error with ferror */ } /* diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index f0b3b1feb0..7122b59b96 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -1747,10 +1747,12 @@ write_eventlog(int level, const char *line, int len) static void write_console(const char *line, int len) { + int rc; + #ifdef WIN32 /* - * WriteConsoleW() will fail of stdout is redirected, so just fall through + * WriteConsoleW() will fail if stdout is redirected, so just fall through * to writing unconverted to the logfile in this case. * * Since we palloc the structure required for conversion, also fall @@ -1788,13 +1790,18 @@ write_console(const char *line, int len) #else /* - * Conversion on non-win32 platform is not implemented yet. It requires + * Conversion on non-win32 platforms is not implemented yet. It requires * non-throw version of pg_do_encoding_conversion(), that converts * unconvertable characters to '?' without errors. */ #endif - write(fileno(stderr), line, len); + /* + * We ignore any error from write() here. We have no useful way to report + * it ... certainly whining on stderr isn't likely to be productive. + */ + rc = write(fileno(stderr), line, len); + (void) rc; } /* @@ -2457,13 +2464,30 @@ send_message_to_server_log(ErrorData *edata) /* * Send data to the syslogger using the chunked protocol + * + * Note: when there are multiple backends writing into the syslogger pipe, + * it's critical that each write go into the pipe indivisibly, and not + * get interleaved with data from other processes. Fortunately, the POSIX + * spec requires that writes to pipes be atomic so long as they are not + * more than PIPE_BUF bytes long. So we divide long messages into chunks + * that are no more than that length, and send one chunk per write() call. + * The collector process knows how to reassemble the chunks. + * + * Because of the atomic write requirement, there are only two possible + * results from write() here: -1 for failure, or the requested number of + * bytes. There is not really anything we can do about a failure; retry would + * probably be an infinite loop, and we can't even report the error usefully. + * (There is noplace else we could send it!) So we might as well just ignore + * the result from write(). However, on some platforms you get a compiler + * warning from ignoring write()'s result, so do a little dance with casting + * rc to void to shut up the compiler. */ static void write_pipe_chunks(char *data, int len, int dest) { PipeProtoChunk p; - int fd = fileno(stderr); + int rc; Assert(len > 0); @@ -2476,7 +2500,8 @@ write_pipe_chunks(char *data, int len, int dest) p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'F' : 'f'); p.proto.len = PIPE_MAX_PAYLOAD; memcpy(p.proto.data, data, PIPE_MAX_PAYLOAD); - write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD); + rc = write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD); + (void) rc; data += PIPE_MAX_PAYLOAD; len -= PIPE_MAX_PAYLOAD; } @@ -2485,7 +2510,8 @@ write_pipe_chunks(char *data, int len, int dest) p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'T' : 't'); p.proto.len = len; memcpy(p.proto.data, data, len); - write(fd, &p, PIPE_HEADER_SIZE + len); + rc = write(fd, &p, PIPE_HEADER_SIZE + len); + (void) rc; } diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 101544800d..5ab736e30b 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -228,6 +228,7 @@ static void handle_sigint(SIGNAL_ARGS) { int save_errno = errno; + int rc; char errbuf[256]; /* if we are waiting for input, longjmp out of it */ @@ -244,11 +245,16 @@ handle_sigint(SIGNAL_ARGS) if (cancelConn != NULL) { if (PQcancel(cancelConn, errbuf, sizeof(errbuf))) - write_stderr("Cancel request sent\n"); + { + rc = write_stderr("Cancel request sent\n"); + (void) rc; /* ignore errors, nothing we can do here */ + } else { - write_stderr("Could not send cancel request: "); - write_stderr(errbuf); + rc = write_stderr("Could not send cancel request: "); + (void) rc; /* ignore errors, nothing we can do here */ + rc = write_stderr(errbuf); + (void) rc; /* ignore errors, nothing we can do here */ } }