From: Josselin Poiret via Guix-patches via <guix-patches@gnu.org>
To: 53063@debbugs.gnu.org
Cc: Josselin Poiret <dev@jpoiret.xyz>
Subject: [bug#53063] [PATCH wip-harden-installer 05/14] installer: Capture external commands output.
Date: Thu, 6 Jan 2022 23:48:03 +0100 [thread overview]
Message-ID: <fb8b136928d2d981eec2f284207b4dc7483077cc.1641507696.git.dev@jpoiret.xyz> (raw)
In-Reply-To: <cover.1641507696.git.dev@jpoiret.xyz>
* gnu/installer/utils.scm (close-fdes-ignore-badf, reset-fds,
run-external-command-with-handler,
run-external-command-with-line-hooks): New variables.
(run-command): Use run-external-command-with-line-hooks.
---
gnu/installer/utils.scm | 154 ++++++++++++++++++++++++++++++++++------
1 file changed, 134 insertions(+), 20 deletions(-)
diff --git a/gnu/installer/utils.scm b/gnu/installer/utils.scm
index 1bff1e1229..878434f074 100644
--- a/gnu/installer/utils.scm
+++ b/gnu/installer/utils.scm
@@ -25,7 +25,9 @@ (define-module (gnu installer utils)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-19)
#:use-module (srfi srfi-34)
+ #:use-module (ice-9 control)
#:use-module (ice-9 match)
+ #:use-module (ice-9 popen)
#:use-module (ice-9 rdelim)
#:use-module (ice-9 regex)
#:use-module (ice-9 format)
@@ -78,37 +80,149 @@ (define (read-percentage percentage)
(and result
(string->number (match:substring result 1)))))
+;; This is needed because there are two close procedures in Guile:
+;; * close, which relocates ports that were using the fd to use a
+;; newly dup'd fd;
+;; * vanilla close-fdes, which does not ignore EBADF, making it
+;; impossible to use it to close all ports.
+(define (close-fdes-ignore-badf fd)
+ (let/ec escape
+ (with-exception-handler
+ (lambda (exn)
+ (if (eq? (exception-kind exn) 'system-error)
+ (let ((args (exception-args exn)))
+ (if (eq? (car (car (cdr (cdr (cdr args)))))
+ 9) ;; EBADF
+ (escape)
+ (raise-exception exn)))
+ (raise-exception exn)))
+ (lambda ()
+ (close-fdes fd)))))
+
+(define (reset-fds in out err)
+ "Resets the stdin, stdout and stderr to IN, OUT and ERR
+respectively, while closing all other open file descriptors."
+ ;; getrlimit is undocumented, but defined in
+ ;; libguile/posix.c.
+ (define maxfds (getrlimit 'nofile))
+ (let loop ((fd 0))
+ (and (< fd maxfds)
+ (begin (unless (or (eq? in fd)
+ (eq? out fd)
+ (eq? err fd))
+ (close-fdes-ignore-badf fd))
+ (loop (+ fd 1)))))
+ (define (next-available fd)
+ (and (< fd maxfds)
+ (if (or (eq? in fd)
+ (eq? out fd)
+ (eq? err fd))
+ (next-available (+ fd 1))
+ fd)))
+ (define dupin (next-available 3))
+ (define dupout (next-available (+ dupin 1)))
+ (define duperr (next-available (+ dupout 1)))
+ (dup2 in dupin)
+ (dup2 out dupout)
+ (dup2 err duperr)
+ (for-each close-fdes-ignore-badf (list in out err))
+ (dup2 dupin 0)
+ (dup2 dupout 1)
+ (dup2 duperr 2)
+ (for-each close-fdes (list dupin dupout duperr))
+ (set-current-input-port (fdes->inport 0))
+ (set-current-output-port (fdes->outport 1))
+ (set-current-error-port (fdes->outport 2)))
+
+(define* (run-external-command-with-handler handler command)
+ "Run command specified by the list COMMAND in a child with output handler
+HANDLER. HANDLER is a procedure taking an input port, to which the command
+will write its standard output and error. Returns the integer status value of
+the child process as returned by waitpid."
+ (match-let (((input . output) (pipe)))
+ (match (primitive-fork)
+ (0 ;; We're in the child
+ (close-port input)
+ (reset-fds
+ (open-fdes "/dev/null" O_WRONLY)
+ ;; Avoid port GC'ing closing the fd by increasing its revealed count.
+ (port->fdes output)
+ (fileno output))
+ (with-exception-handler
+ (lambda (exn)
+ ((@@ (ice-9 exceptions) format-exception) (current-error-port)
+ exn)
+ (primitive-_exit 1))
+ (lambda ()
+ (apply execlp (car command) command)
+ (primitive-_exit 1))))
+ (pid
+ (close-port output)
+ (handler input)
+ (close-port input)
+ (cdr (waitpid pid))))))
+
+(define (run-external-command-with-line-hooks line-hooks command)
+ "Run command specified by ARGS in a child, processing each output line with
+the procedures in LINE-HOOKS. Returns the integer status value of
+the child process as returned by waitpid."
+ (define (handler input)
+ (and (and=> (get-line input)
+ (lambda (line)
+ (if (eof-object? line)
+ #f
+ (begin (for-each (lambda (f) (f line))
+ (append line-hooks
+ %default-installer-line-hooks))
+ #t))))
+ (handler input)))
+ (run-external-command-with-handler handler command))
+
(define* (run-command command)
"Run COMMAND, a list of strings. Return true if COMMAND exited
successfully, #f otherwise."
- (define env (environ))
-
(define (pause)
(format #t (G_ "Press Enter to continue.~%"))
(send-to-clients '(pause))
- (environ env) ;restore environment variables
(match (select (cons (current-input-port) (current-clients))
'() '())
(((port _ ...) _ _)
(read-line port))))
- (setenv "PATH" "/run/current-system/profile/bin")
-
- (guard (c ((invoke-error? c)
- (newline)
- (format (current-error-port)
- (G_ "Command failed with exit code ~a.~%")
- (invoke-error-exit-status c))
- (installer-log-line "command ~s failed with exit code ~a"
- command (invoke-error-exit-status c))
- (pause)
- #f))
- (installer-log-line "running command ~s" command)
- (apply invoke command)
- (installer-log-line "command ~s succeeded" command)
- (newline)
- (pause)
- #t))
+ (installer-log-line "running command ~s" command)
+ (define result (run-external-command-with-line-hooks
+ (list %display-line-hook)
+ command))
+ (define exit-val (status:exit-val result))
+ (define term-sig (status:term-sig result))
+ (define stop-sig (status:stop-sig result))
+ (define succeeded?
+ (cond
+ ((and exit-val (not (zero? exit-val)))
+ (installer-log-line "command ~s exited with value ~a"
+ command exit-val)
+ (format #t (G_ "Command ~s exited with value ~a")
+ command exit-val)
+ #f)
+ (term-sig
+ (installer-log-line "command ~s killed by signal ~a"
+ command term-sig)
+ (format #t (G_ "Command ~s killed by signal ~a")
+ command term-sig)
+ #f)
+ (stop-sig
+ (installer-log-line "command ~s stopped by signal ~a"
+ command stop-sig)
+ (format #t (G_ "Command ~s stopped by signal ~a")
+ command stop-sig)
+ #f)
+ (else
+ (installer-log-line "command ~s succeeded" command)
+ (format #t (G_ "Command ~s succeeded") command)
+ #t)))
+ (newline)
+ (pause)
+ succeeded?)
\f
;;;
--
2.34.0
next prev parent reply other threads:[~2022-01-06 22:50 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-06 22:45 [bug#53063] [PATCH wip-harden-installer 00/14] General improvements to the installer Josselin Poiret via Guix-patches via
2022-01-06 22:47 ` [bug#53063] [PATCH wip-harden-installer 01/14] installer: Use define instead of let at top-level Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 02/14] installer: Generalize logging facility Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 03/14] installer: Use new installer-log-line everywhere Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 04/14] installer: Un-export syslog syntax Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` Josselin Poiret via Guix-patches via [this message]
2022-01-07 13:47 ` [bug#53063] [PATCH wip-harden-installer 00/14] General improvements to the installer Ludovic Courtès
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 06/14] installer: Disable automatic finalization for child thread Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 07/14] installer: Add installer-specific run command process Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 08/14] installer: Use run-command-in-installer in (gnu installer parted) Josselin Poiret via Guix-patches via
2022-01-07 10:58 ` Mathieu Othacehe
2022-01-07 11:46 ` Josselin Poiret via Guix-patches via
2022-01-15 13:49 ` [bug#53063] [PATCH v2 wip-harden-installer 00/18] General improvements to the installer Josselin Poiret via Guix-patches via
2022-01-15 13:49 ` [bug#53063] [PATCH v2 wip-harden-installer 01/18] installer: Use define instead of let at top-level Josselin Poiret via Guix-patches via
2022-01-15 13:49 ` [bug#53063] [PATCH v2 wip-harden-installer 02/18] installer: Generalize logging facility Josselin Poiret via Guix-patches via
2022-01-15 13:49 ` [bug#53063] [PATCH v2 wip-harden-installer 03/18] installer: Use new installer-log-line everywhere Josselin Poiret via Guix-patches via
2022-01-15 13:49 ` [bug#53063] [PATCH v2 wip-harden-installer 04/18] installer: Un-export syslog syntax Josselin Poiret via Guix-patches via
2022-01-15 13:49 ` [bug#53063] [PATCH v2 wip-harden-installer 05/18] installer: Keep PATH inside the install container Josselin Poiret via Guix-patches via
2022-01-15 13:49 ` [bug#53063] [PATCH v2 wip-harden-installer 06/18] installer: Remove specific logging code Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 07/18] installer: Capture external commands output Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 08/18] installer: Add installer-specific run command process Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 09/18] installer: Use run-command-in-installer in (gnu installer parted) Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 10/18] installer: Raise condition when mklabel fails Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 11/18] installer: Fix run-file-textbox-page when edit-button is #f Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 12/18] installer: Replace run-command by invoke in newt/page.scm Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 13/18] installer: Add nano to PATH Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 14/18] installer: Use named prompt to abort or break installer steps Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 15/18] installer: Add error page when running external commands Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 16/18] installer: Use dynamic-wind to setup installer Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 17/18] installer: Turn passwords into opaque records Josselin Poiret via Guix-patches via
2022-01-15 13:50 ` [bug#53063] [PATCH v2 wip-harden-installer 18/18] installer: Make dump archive creation optional and selective Josselin Poiret via Guix-patches via
2022-01-17 10:16 ` [bug#53063] [PATCH wip-harden-installer 00/14] General improvements to the installer Mathieu Othacehe
2022-01-31 17:45 ` [bug#53063] [PATCH] installer: Use system-wide guix for system init Josselin Poiret via Guix-patches via
2022-02-02 15:50 ` bug#53063: " Mathieu Othacehe
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 09/14] installer: Use the command capturing facility for guix init Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 10/14] installer: Raise condition when mklabel fails Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 11/14] installer: Fix run-file-textbox-page when edit-button is #f Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 12/14] installer: Replace run-command by invoke in newt/page.scm Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 13/14] installer: Use named prompt to abort or break installer steps Josselin Poiret via Guix-patches via
2022-01-06 22:48 ` [bug#53063] [PATCH wip-harden-installer 14/14] installer: Add confirmation page when running external commands Josselin Poiret via Guix-patches via
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fb8b136928d2d981eec2f284207b4dc7483077cc.1641507696.git.dev@jpoiret.xyz \
--to=guix-patches@gnu.org \
--cc=53063@debbugs.gnu.org \
--cc=dev@jpoiret.xyz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/guix.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.