diff mbox series

pkt-line: do not report packet write errors twice

Message ID 64b81865fdfcc505b6aa3e6ebaebf3b9ccb36eb1.1618513583.git.matheus.bernardino@usp.br (mailing list archive)
State Superseded
Headers show
Series pkt-line: do not report packet write errors twice | expand

Commit Message

Matheus Tavares Bernardino April 15, 2021, 7:10 p.m. UTC
On write() errors, packet_write() dies with the same error message that
is already printed by its callee, packet_write_gently(). This produces
an unnecessarily verbose and repetitive output:

error: packet write failed
fatal: packet write failed: <strerror() message>

In addition to that, packet_write_gently() does not always fulfill its
caller expectation that errno will be properly set before a non-zero
return. In particular, that is not the case for a "data exceeds max
packet size" error. So, in this case, packet_write() will call
die_errno() and print a strerror(errno) message that might be totally
unrelated to the actual error.

Fix both those issues by turning packet_write() and
packet_write_gently() into wrappers to a lower level function which is
now responsible to either error() or die() as requested by its caller.

Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
---
 pkt-line.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

Comments

Junio C Hamano April 15, 2021, 8:06 p.m. UTC | #1
Matheus Tavares <matheus.bernardino@usp.br> writes:

> On write() errors, packet_write() dies with the same error message that
> is already printed by its callee, packet_write_gently(). This produces
> an unnecessarily verbose and repetitive output:
>
> error: packet write failed
> fatal: packet write failed: <strerror() message>
>
> In addition to that, packet_write_gently() does not always fulfill its
> caller expectation that errno will be properly set before a non-zero
> return. In particular, that is not the case for a "data exceeds max
> packet size" error. So, in this case, packet_write() will call
> die_errno() and print a strerror(errno) message that might be totally
> unrelated to the actual error.
>
> Fix both those issues by turning packet_write() and
> packet_write_gently() into wrappers to a lower level function which is
> now responsible to either error() or die() as requested by its caller.
>
> Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
> ---
>  pkt-line.c | 27 ++++++++++++++++++++-------
>  1 file changed, 20 insertions(+), 7 deletions(-)

Nicely done.  Duplicated error message literals do look, eh,
repetitious, though.

I wonder if something like this on top would be an improvement.

Upon seeing "return error(_(VARIABLE_NAME))", it may be distracting
that you now have to move to where the actual message is defined
while following the logic of the code, but as long as the variable
name captures the essense of what the message says, it may be OK.

I dunno.


 pkt-line.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git c/pkt-line.c w/pkt-line.c
index 39c9ca4212..d357c74fcd 100644
--- c/pkt-line.c
+++ w/pkt-line.c
@@ -199,12 +199,16 @@ static int do_packet_write(const int fd_out, cons
 {
 	char header[4];
 	size_t packet_size;
+	static const char size_error_message[] =
+		N_("packet write failed - data exceeds max packet size");
+	static const char write_error_message[] =
+		N_("packet write failed");
 
 	if (size > LARGE_PACKET_DATA_MAX) {
 		if (gentle)
-			return error(_("packet write failed - data exceeds max packet size"));
+			return error(_(size_error_message));
 		else
-			die(_("packet write failed - data exceeds max packet size"));
+			die(_(size_error_message));
 	}
 
 	packet_trace(buf, size, 1);
@@ -222,9 +226,9 @@ static int do_packet_write(const int fd_out, const
 	if (write_in_full(fd_out, header, 4) < 0 ||
 	    write_in_full(fd_out, buf, size) < 0) {
 		if (gentle)
-			return error_errno(_("packet write failed"));
+			return error_errno(_(write_error_message));
 		else
-			die_errno(_("packet write failed"));
+			die_errno(_(write_error_message));
 	}
 	return 0;
 }
Matheus Tavares Bernardino April 15, 2021, 8:24 p.m. UTC | #2
On Thu, Apr 15, 2021 at 5:06 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Matheus Tavares <matheus.bernardino@usp.br> writes:
>
> > On write() errors, packet_write() dies with the same error message that
> > is already printed by its callee, packet_write_gently(). This produces
> > an unnecessarily verbose and repetitive output:
> >
> > error: packet write failed
> > fatal: packet write failed: <strerror() message>
> >
> > In addition to that, packet_write_gently() does not always fulfill its
> > caller expectation that errno will be properly set before a non-zero
> > return. In particular, that is not the case for a "data exceeds max
> > packet size" error. So, in this case, packet_write() will call
> > die_errno() and print a strerror(errno) message that might be totally
> > unrelated to the actual error.
> >
> > Fix both those issues by turning packet_write() and
> > packet_write_gently() into wrappers to a lower level function which is
> > now responsible to either error() or die() as requested by its caller.
> >
> > Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
> > ---
> >  pkt-line.c | 27 ++++++++++++++++++++-------
> >  1 file changed, 20 insertions(+), 7 deletions(-)
>
> Nicely done.  Duplicated error message literals do look, eh,
> repetitious, though.
>
> I wonder if something like this on top would be an improvement.
>
> Upon seeing "return error(_(VARIABLE_NAME))", it may be distracting
> that you now have to move to where the actual message is defined
> while following the logic of the code, but as long as the variable
> name captures the essense of what the message says, it may be OK.
>
> I dunno.
>
>
>  pkt-line.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git c/pkt-line.c w/pkt-line.c
> index 39c9ca4212..d357c74fcd 100644
> --- c/pkt-line.c
> +++ w/pkt-line.c
> @@ -199,12 +199,16 @@ static int do_packet_write(const int fd_out, cons
>  {
>         char header[4];
>         size_t packet_size;
> +       static const char size_error_message[] =
> +               N_("packet write failed - data exceeds max packet size");
> +       static const char write_error_message[] =
> +               N_("packet write failed");
>
>         if (size > LARGE_PACKET_DATA_MAX) {
>                 if (gentle)
> -                       return error(_("packet write failed - data exceeds max packet size"));
> +                       return error(_(size_error_message));
>                 else
> -                       die(_("packet write failed - data exceeds max packet size"));
> +                       die(_(size_error_message));
>         }
>
>         packet_trace(buf, size, 1);
> @@ -222,9 +226,9 @@ static int do_packet_write(const int fd_out, const
>         if (write_in_full(fd_out, header, 4) < 0 ||
>             write_in_full(fd_out, buf, size) < 0) {
>                 if (gentle)
> -                       return error_errno(_("packet write failed"));
> +                       return error_errno(_(write_error_message));
>                 else
> -                       die_errno(_("packet write failed"));
> +                       die_errno(_(write_error_message));
>         }
>         return 0;
>  }

Nice! :) Maybe we could also avoid the static strings without
repeating the literals by making `do_packet_write()` receive a `struct
strbuf *err` and save the error message in it? Then the two callers
can decide whether to pass it to error() or die() accordingly.
Junio C Hamano April 15, 2021, 8:32 p.m. UTC | #3
Matheus Tavares Bernardino <matheus.bernardino@usp.br> writes:

> Nice! :) Maybe we could also avoid the static strings without
> repeating the literals by making `do_packet_write()` receive a `struct
> strbuf *err` and save the error message in it? Then the two callers
> can decide whether to pass it to error() or die() accordingly.

Sorry, but I do not understand what benefit we are trying to gain by
introducing an extra strbuf (which I assume is used to strbuf_add()
the error message into).  Wouldn't the caller need two messages and
flip between <error,error_errno> vs <die,die_errno> pair?
Matheus Tavares Bernardino April 15, 2021, 8:48 p.m. UTC | #4
On Thu, Apr 15, 2021 at 5:32 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Matheus Tavares Bernardino <matheus.bernardino@usp.br> writes:
>
> > Nice! :) Maybe we could also avoid the static strings without
> > repeating the literals by making `do_packet_write()` receive a `struct
> > strbuf *err` and save the error message in it? Then the two callers
> > can decide whether to pass it to error() or die() accordingly.
>
> Sorry, but I do not understand what benefit we are trying to gain by
> introducing an extra strbuf (which I assume is used to strbuf_add()
> the error message into).  Wouldn't the caller need two messages and
> flip between <error,error_errno> vs <die,die_errno> pair?

Hmm, I'm not sure I understand what you mean by the two messages, but
what I was thinking of is something like this (on top of my original
patch):

diff --git a/pkt-line.c b/pkt-line.c
index 39c9ca4212..98304ce374 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -195,16 +195,14 @@ int packet_write_fmt_gently(int fd, const char *fmt, ...)
 }

 static int do_packet_write(const int fd_out, const char *buf, size_t size,
-			   int gentle)
+			   struct strbuf *err)
 {
 	char header[4];
 	size_t packet_size;

 	if (size > LARGE_PACKET_DATA_MAX) {
-		if (gentle)
-			return error(_("packet write failed - data exceeds max packet size"));
-		else
-			die(_("packet write failed - data exceeds max packet size"));
+		strbuf_addstr(err, _("packet write failed - data exceeds max packet size"));
+		return -1;
 	}

 	packet_trace(buf, size, 1);
@@ -221,22 +219,28 @@ static int do_packet_write(const int fd_out, const char *buf, size_t size,

 	if (write_in_full(fd_out, header, 4) < 0 ||
 	    write_in_full(fd_out, buf, size) < 0) {
-		if (gentle)
-			return error_errno(_("packet write failed"));
-		else
-			die_errno(_("packet write failed"));
+		strbuf_addf(err, _("packet write failed: %s"), strerror(errno));
+		return -1;
 	}
 	return 0;
 }

 static int packet_write_gently(const int fd_out, const char *buf, size_t size)
 {
-	return do_packet_write(fd_out, buf, size, 1);
+	struct strbuf err = STRBUF_INIT;
+	if (do_packet_write(fd_out, buf, size, &err)) {
+		error("%s", err.buf);
+		strbuf_release(&err);
+		return -1;
+	}
+	return 0;
 }

 void packet_write(int fd_out, const char *buf, size_t size)
 {
-	do_packet_write(fd_out, buf, size, 0);
+	struct strbuf err = STRBUF_INIT;
+	if (do_packet_write(fd_out, buf, size, &err))
+		die("%s", err.buf);
 }

 void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
Junio C Hamano April 15, 2021, 8:56 p.m. UTC | #5
Matheus Tavares <matheus.bernardino@usp.br> writes:

> On Thu, Apr 15, 2021 at 5:32 PM Junio C Hamano <gitster@pobox.com> wrote:
>>
>> Matheus Tavares Bernardino <matheus.bernardino@usp.br> writes:
>>
>> > Nice! :) Maybe we could also avoid the static strings without
>> > repeating the literals by making `do_packet_write()` receive a `struct
>> > strbuf *err` and save the error message in it? Then the two callers
>> > can decide whether to pass it to error() or die() accordingly.
>>
>> Sorry, but I do not understand what benefit we are trying to gain by
>> introducing an extra strbuf (which I assume is used to strbuf_add()
>> the error message into).  Wouldn't the caller need two messages and
>> flip between <error,error_errno> vs <die,die_errno> pair?
>
> Hmm, I'm not sure I understand what you mean by the two messages, but
> what I was thinking of is something like this (on top of my original
> patch):

Ah, OK, you meant that you'd make do_packet_write() handle
die/error_errno itself by manually calling strerror(errno).

One small downside with the approach is that do_packet_write() needs
to hardcode how die/error_errno() mixes the strerror() with the
caller supplied error message, but I do not care too strongly either
way.  My original motivation of suggesting the rewrite was to avoid
overlong lines in the main flow of the code by replacing the long
messages with variable names that are much shorter, so as long as
that is done, I am fine either way.

Thanks.
diff mbox series

Patch

diff --git a/pkt-line.c b/pkt-line.c
index 0194137528..39c9ca4212 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -194,13 +194,18 @@  int packet_write_fmt_gently(int fd, const char *fmt, ...)
 	return status;
 }
 
-static int packet_write_gently(const int fd_out, const char *buf, size_t size)
+static int do_packet_write(const int fd_out, const char *buf, size_t size,
+			   int gentle)
 {
 	char header[4];
 	size_t packet_size;
 
-	if (size > LARGE_PACKET_DATA_MAX)
-		return error(_("packet write failed - data exceeds max packet size"));
+	if (size > LARGE_PACKET_DATA_MAX) {
+		if (gentle)
+			return error(_("packet write failed - data exceeds max packet size"));
+		else
+			die(_("packet write failed - data exceeds max packet size"));
+	}
 
 	packet_trace(buf, size, 1);
 	packet_size = size + 4;
@@ -215,15 +220,23 @@  static int packet_write_gently(const int fd_out, const char *buf, size_t size)
 	 */
 
 	if (write_in_full(fd_out, header, 4) < 0 ||
-	    write_in_full(fd_out, buf, size) < 0)
-		return error(_("packet write failed"));
+	    write_in_full(fd_out, buf, size) < 0) {
+		if (gentle)
+			return error_errno(_("packet write failed"));
+		else
+			die_errno(_("packet write failed"));
+	}
 	return 0;
 }
 
+static int packet_write_gently(const int fd_out, const char *buf, size_t size)
+{
+	return do_packet_write(fd_out, buf, size, 1);
+}
+
 void packet_write(int fd_out, const char *buf, size_t size)
 {
-	if (packet_write_gently(fd_out, buf, size))
-		die_errno(_("packet write failed"));
+	do_packet_write(fd_out, buf, size, 0);
 }
 
 void packet_buf_write(struct strbuf *buf, const char *fmt, ...)