Message ID | 20220625171847.29104-1-mail@cbaines.net |
---|---|
State | New |
Headers |
Return-Path: <guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org> X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id DD5BC27BBEA; Sat, 25 Jun 2022 18:19:18 +0100 (BST) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=BAYES_00,MAILING_LIST_MULTI, SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 9789E27BBE9 for <patchwork@mira.cbaines.net>; Sat, 25 Jun 2022 18:19:18 +0100 (BST) Received: from localhost ([::1]:60974 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org>) id 1o59RF-00010f-PQ for patchwork@mira.cbaines.net; Sat, 25 Jun 2022 13:19:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47400) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1o59R0-00010W-Pt for guix-patches@gnu.org; Sat, 25 Jun 2022 13:19:02 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:52258) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1o59R0-00040u-Hf for guix-patches@gnu.org; Sat, 25 Jun 2022 13:19:02 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1o59R0-0006mN-BD for guix-patches@gnu.org; Sat, 25 Jun 2022 13:19:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#56218] [PATCH] guix: inferior: Fix the behaviour of open-inferior #:error-port. Resent-From: Christopher Baines <mail@cbaines.net> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces@debbugs.gnu.org> Resent-CC: guix-patches@gnu.org Resent-Date: Sat, 25 Jun 2022 17:19:02 +0000 Resent-Message-ID: <handler.56218.B.165617753426039@debbugs.gnu.org> Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 56218 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 56218@debbugs.gnu.org X-Debbugs-Original-To: guix-patches@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.165617753426039 (code B ref -1); Sat, 25 Jun 2022 17:19:02 +0000 Received: (at submit) by debbugs.gnu.org; 25 Jun 2022 17:18:54 +0000 Received: from localhost ([127.0.0.1]:46155 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces@debbugs.gnu.org>) id 1o59Qs-0006lv-By for submit@debbugs.gnu.org; Sat, 25 Jun 2022 13:18:54 -0400 Received: from lists.gnu.org ([209.51.188.17]:40238) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <mail@cbaines.net>) id 1o59Qp-0006ll-Va for submit@debbugs.gnu.org; Sat, 25 Jun 2022 13:18:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47384) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <mail@cbaines.net>) id 1o59Qp-00010N-Q8 for guix-patches@gnu.org; Sat, 25 Jun 2022 13:18:51 -0400 Received: from mira.cbaines.net ([212.71.252.8]:36428) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from <mail@cbaines.net>) id 1o59Qo-00040D-84 for guix-patches@gnu.org; Sat, 25 Jun 2022 13:18:51 -0400 Received: from localhost (unknown [IPv6:2a02:8010:68c1:0:54d1:d5d4:280e:f699]) by mira.cbaines.net (Postfix) with ESMTPSA id ED17E27BBE9 for <guix-patches@gnu.org>; Sat, 25 Jun 2022 18:18:47 +0100 (BST) Received: from localhost (localhost [local]) by localhost (OpenSMTPD) with ESMTPA id 1fba1de2 for <guix-patches@gnu.org>; Sat, 25 Jun 2022 17:18:47 +0000 (UTC) From: Christopher Baines <mail@cbaines.net> Date: Sat, 25 Jun 2022 18:18:47 +0100 Message-Id: <20220625171847.29104-1-mail@cbaines.net> X-Mailer: git-send-email 2.36.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=212.71.252.8; envelope-from=mail@cbaines.net; helo=mira.cbaines.net X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, UNPARSEABLE_RELAY=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: <guix-patches.gnu.org> List-Unsubscribe: <https://lists.gnu.org/mailman/options/guix-patches>, <mailto:guix-patches-request@gnu.org?subject=unsubscribe> List-Archive: <https://lists.gnu.org/archive/html/guix-patches> List-Post: <mailto:guix-patches@gnu.org> List-Help: <mailto:guix-patches-request@gnu.org?subject=help> List-Subscribe: <https://lists.gnu.org/mailman/listinfo/guix-patches>, <mailto:guix-patches-request@gnu.org?subject=subscribe> Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" <guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org> X-getmail-retrieved-from-mailbox: Patches |
Series |
[bug#56218] guix: inferior: Fix the behaviour of open-inferior #:error-port.
|
|
Commit Message
Christopher Baines
June 25, 2022, 5:18 p.m. UTC
This should be the error port used by the inferior process, but currently it's either stderr if #:error-port is a file port, or /dev/null otherwise. I'm looking at this as the Guix Data Service uses this behaviour to record and display logs from inferior processes. * guix/inferior.scm (open-bidirectional-pipe): Call dup2 for file descriptor 2, passing either the file number for the current error port, or a file descriptor for /dev/null. --- guix/inferior.scm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
Comments
Christopher Baines schreef op za 25-06-2022 om 18:18 [+0100]: > (close-port parent) > (close-fdes 0) > (close-fdes 1) > + (close-fdes 2) > (dup2 (fileno child) 0) > (dup2 (fileno child) 1) > ;; Mimic 'open-pipe*'. > - (unless (file-port? (current-error-port)) > - (close-fdes 2) > - (dup2 (open-fdes "/dev/null" O_WRONLY) 2)) > + (dup2 (if (file-port? (current-error-port)) > + (fileno (current-error-port)) > + (open-fdes "/dev/null" O_WRONLY)) > + 2) I don't this would work if (current-error-port) has fd 1. Would move->fdes be appropriate here? The following seems less fragile (*) to me (untested, also I didn't look at the context) (move->fdes [child port] 0) (move->fdes (dup [child port]) 1) (if (file-port? (current-error-port)) (move->fdes (current-error-port) 2) (move->fdes (open-file "/dev/null" O_WRONLY) 2)) (*): move->fdes automatically moves ports out of the way. Also, if one of the moves fails, then at least (current-output-port) etc will still have a correct fd so some error reporting should be possible Greetings, Maxime.
Maxime Devos schreef op za 25-06-2022 om 19:50 [+0200]:
> I don't this would work if (current-error-port) has fd 1. [...]
TBC, I never worked with file descriptor manipulation and process
forking much, and I didn't look at the surrounding code, so don't take
my word for it.
Hi Christopher, Christopher Baines <mail@cbaines.net> skribis: > This should be the error port used by the inferior process, but currently it's > either stderr if #:error-port is a file port, or /dev/null otherwise. That’s still the case with this patch, no? The patch does make a difference when (current-error-port) wraps a file descriptor other than 2 though. > +++ b/guix/inferior.scm > @@ -156,12 +156,14 @@ (define (open-bidirectional-pipe command . args) > (close-port parent) > (close-fdes 0) > (close-fdes 1) > + (close-fdes 2) > (dup2 (fileno child) 0) > (dup2 (fileno child) 1) > ;; Mimic 'open-pipe*'. > - (unless (file-port? (current-error-port)) > - (close-fdes 2) > - (dup2 (open-fdes "/dev/null" O_WRONLY) 2)) > + (dup2 (if (file-port? (current-error-port)) > + (fileno (current-error-port)) > + (open-fdes "/dev/null" O_WRONLY)) > + 2) If (current-error-port) wraps FD 2 when the function is called, then, by the time we reach (dup2 … 2), the FD behind (current-error-port) has be closed; we end up doing (dup2 2 2), but FD 2 is closed, so we get EBADF. Or am I misunderstanding? Perhaps we should add one test for each case (error port is a file port vs. error port is another kind of port) in ‘tests/inferior.scm’. Thanks, Ludo’.
Maxime Devos <maximedevos@telenet.be> writes: > [[PGP Signed Part:Undecided]] > Christopher Baines schreef op za 25-06-2022 om 18:18 [+0100]: >> (close-port parent) >> (close-fdes 0) >> (close-fdes 1) >> + (close-fdes 2) >> (dup2 (fileno child) 0) >> (dup2 (fileno child) 1) >> ;; Mimic 'open-pipe*'. >> - (unless (file-port? (current-error-port)) >> - (close-fdes 2) >> - (dup2 (open-fdes "/dev/null" O_WRONLY) 2)) >> + (dup2 (if (file-port? (current-error-port)) >> + (fileno (current-error-port)) >> + (open-fdes "/dev/null" O_WRONLY)) >> + 2) > > I don't this would work if (current-error-port) has fd 1. Would > move->fdes be appropriate here? The following seems less fragile (*) > to me (untested, also I didn't look at the context) > > (move->fdes [child port] 0) > (move->fdes (dup [child port]) 1) > (if (file-port? (current-error-port)) > (move->fdes (current-error-port) 2) > (move->fdes (open-file "/dev/null" O_WRONLY) 2)) > > > (*): move->fdes automatically moves ports out of the way. Also, if one > of the moves fails, then at least (current-output-port) etc will still > have a correct fd so some error reporting should be possible Maybe. I haven't actually tried this yet, but the docs seem to suggest it would work. Thanks, Chris
Ludovic Courtès <ludo@gnu.org> writes: > Hi Christopher, > > Christopher Baines <mail@cbaines.net> skribis: > >> This should be the error port used by the inferior process, but currently it's >> either stderr if #:error-port is a file port, or /dev/null otherwise. > > That’s still the case with this patch, no? > > The patch does make a difference when (current-error-port) wraps a file > descriptor other than 2 though. Maybe this sentance is a little unclear. What I'm trying to say is that passing a port as #:error-port doesn't really work. There's no scenario where the output actually goes to the port you provide, though it can have some effect. >> +++ b/guix/inferior.scm >> @@ -156,12 +156,14 @@ (define (open-bidirectional-pipe command . args) >> (close-port parent) >> (close-fdes 0) >> (close-fdes 1) >> + (close-fdes 2) >> (dup2 (fileno child) 0) >> (dup2 (fileno child) 1) >> ;; Mimic 'open-pipe*'. >> - (unless (file-port? (current-error-port)) >> - (close-fdes 2) >> - (dup2 (open-fdes "/dev/null" O_WRONLY) 2)) >> + (dup2 (if (file-port? (current-error-port)) >> + (fileno (current-error-port)) >> + (open-fdes "/dev/null" O_WRONLY)) >> + 2) > > If (current-error-port) wraps FD 2 when the function is called, then, by > the time we reach (dup2 … 2), the FD behind (current-error-port) has be > closed; we end up doing (dup2 2 2), but FD 2 is closed, so we get EBADF. > > Or am I misunderstanding? That sounds reasonable, I've only tested this change in the scenario when the #:error-port isn't stderr, and I mostly adapted this from what I thought open-pipe* did. Maxime suggested using move->fdes, so maybe this would be an improved version: ;; Mimic 'open-pipe*'. (if (file-port? (current-error-port)) (unless (eq? (fileno (current-error-port)) 2) (move-fdes (current-error-port) 2)) (move->fdes (open-file "/dev/null" O_WRONLY) 2)) > Perhaps we should add one test for each case (error port is a file port > vs. error port is another kind of port) in ‘tests/inferior.scm’. Yep, sounds good. Thanks, Chris
Hi, Christopher Baines <mail@cbaines.net> skribis: > Ludovic Courtès <ludo@gnu.org> writes: > >> Hi Christopher, >> >> Christopher Baines <mail@cbaines.net> skribis: >> >>> This should be the error port used by the inferior process, but currently it's >>> either stderr if #:error-port is a file port, or /dev/null otherwise. >> >> That’s still the case with this patch, no? >> >> The patch does make a difference when (current-error-port) wraps a file >> descriptor other than 2 though. > > Maybe this sentance is a little unclear. > > What I'm trying to say is that passing a port as #:error-port doesn't > really work. There's no scenario where the output actually goes to the > port you provide, though it can have some effect. OK, I think I got it. >>> + (dup2 (if (file-port? (current-error-port)) >>> + (fileno (current-error-port)) >>> + (open-fdes "/dev/null" O_WRONLY)) >>> + 2) >> >> If (current-error-port) wraps FD 2 when the function is called, then, by >> the time we reach (dup2 … 2), the FD behind (current-error-port) has be >> closed; we end up doing (dup2 2 2), but FD 2 is closed, so we get EBADF. >> >> Or am I misunderstanding? > > That sounds reasonable, I've only tested this change in the scenario > when the #:error-port isn't stderr, and I mostly adapted this from what > I thought open-pipe* did. > > Maxime suggested using move->fdes, so maybe this would be an improved > version: > > ;; Mimic 'open-pipe*'. > (if (file-port? (current-error-port)) > (unless (eq? (fileno (current-error-port)) 2) > (move-fdes (current-error-port) 2)) > (move->fdes (open-file "/dev/null" O_WRONLY) 2)) I prefer the original version: I find it clearer (it’s low-level) and probably more robust (thinking through the port/FD interaction needs is more demanding :-)). >> Perhaps we should add one test for each case (error port is a file port >> vs. error port is another kind of port) in ‘tests/inferior.scm’. > > Yep, sounds good. To sum up: I think it’s a welcome change, and it’s even more welcome with a couple of tests to make sure it behaves the way we think it does. Thanks! Ludo’.
Ludovic Courtès <ludo@gnu.org> writes: >>>> + (dup2 (if (file-port? (current-error-port)) >>>> + (fileno (current-error-port)) >>>> + (open-fdes "/dev/null" O_WRONLY)) >>>> + 2) >>> >>> If (current-error-port) wraps FD 2 when the function is called, then, by >>> the time we reach (dup2 … 2), the FD behind (current-error-port) has be >>> closed; we end up doing (dup2 2 2), but FD 2 is closed, so we get EBADF. >>> >>> Or am I misunderstanding? >> >> That sounds reasonable, I've only tested this change in the scenario >> when the #:error-port isn't stderr, and I mostly adapted this from what >> I thought open-pipe* did. >> >> Maxime suggested using move->fdes, so maybe this would be an improved >> version: >> >> ;; Mimic 'open-pipe*'. >> (if (file-port? (current-error-port)) >> (unless (eq? (fileno (current-error-port)) 2) >> (move-fdes (current-error-port) 2)) >> (move->fdes (open-file "/dev/null" O_WRONLY) 2)) > > I prefer the original version: I find it clearer (it’s low-level) and > probably more robust (thinking through the port/FD interaction needs is > more demanding :-)). > >>> Perhaps we should add one test for each case (error port is a file port >>> vs. error port is another kind of port) in ‘tests/inferior.scm’. >> >> Yep, sounds good. > > To sum up: I think it’s a welcome change, and it’s even more welcome > with a couple of tests to make sure it behaves the way we think it does. I've gone ahead and pushed a fix plus some tests as a9fd06121240c78071a398dd1e0ddb47553f3809. The tests probably aren't great, but I think the do cover the #:error-port behaviour.
diff --git a/guix/inferior.scm b/guix/inferior.scm index 54200b75e4..e36806ac84 100644 --- a/guix/inferior.scm +++ b/guix/inferior.scm @@ -156,12 +156,14 @@ (define (open-bidirectional-pipe command . args) (close-port parent) (close-fdes 0) (close-fdes 1) + (close-fdes 2) (dup2 (fileno child) 0) (dup2 (fileno child) 1) ;; Mimic 'open-pipe*'. - (unless (file-port? (current-error-port)) - (close-fdes 2) - (dup2 (open-fdes "/dev/null" O_WRONLY) 2)) + (dup2 (if (file-port? (current-error-port)) + (fileno (current-error-port)) + (open-fdes "/dev/null" O_WRONLY)) + 2) (apply execlp command command args)) (lambda () (primitive-_exit 127))))