Compare commits

...

20 Commits

Author SHA1 Message Date
Josselin Poiret
bc65f83184 installer: Use system-wide guix for system init.
* gnu/installer.scm (installer-program): Remove dependency on the guix
package for the PATH.
* gnu/installer/final.scm (install-system): Set PATH inside container
to /run/current-system/profile/bin/.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-02-02 12:07:08 +01:00
Josselin Poiret
1e2f0cca1a installer: Make dump archive creation optional and selective.
* gnu/installer.scm (installer-program): Let the installer customize
the dump archive.
* gnu/installer/dump.scm (prepare-dump, make-dump): Split make-dump in
prepare-dump, which copies the files necessary for the dump, and
make-dump which creates the archive.
* gnu/installer/record.scm (installer): Add report-page field.  Change
documented return value of exit-error.
* gnu/installer/newt.scm (exit-error): Change arguments to be a string
containing the error.  Let the user choose between exiting and
initiating a dump.
(report-page): Add new variable.
* gnu/installer/newt/page.scm (run-dump-page): New variable.
* gnu/installer/newt/dump.scm: Delete it.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 11:01:46 +01:00
Josselin Poiret
237a0e61e2 installer: Turn passwords into opaque records.
* gnu/installer/user.scm (<secret>, secret?, make-secret,
secret-content): Add opaque <secret> record that boxes its contents,
with a custom printer that doesn't display anything.
* gnu/installer/newt/user.scm (run-user-add-page, run-user-page): Box
it.
* gnu/installer/final.scm (create-user-database): Unbox it.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:49:22 +01:00
Josselin Poiret
16b2bd9d04 installer: Use dynamic-wind to setup installer.
* gnu/installer.scm (installer-program): Use dynamic-wind, so that
completely uncaught exceptions can be printed properly.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:48:21 +01:00
Josselin Poiret
98d23fd53a installer: Add error page when running external commands.
* gnu/installer/newt.scm (newt-run-command): Add it.
* gnu/installer/newt/page.scm (%ok-button, %exit-button,
%default-buttons, make-newt-buttons, run-textbox-page): Add them.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
6ae25c00f6 installer: Use named prompt to abort or break installer steps.
* gnu/installer/steps.scm (run-installer-steps): Set up
'installer-step prompt.
* gnu/installer/newt/ethernet.scm (run-ethernet-page)
* gnu/installer/newt/final.scm (run-config-display-page,
run-install-failed-page)
* gnu/installer/newt/keymap.scm (run-layout-page, run-variant-page)
* gnu/installer/newt/locale.scm (run-language-page,
run-territory-page, run-codeset-page, run-modifier-page,
run-locale-page)
* gnu/installer/newt/network.scm (run-technology-page,
wait-service-online)
* gnu/installer/newt/page.scm (run-listbox-selection-page,
run-checkbox-tree-page)
* gnu/installer/newt/partition.scm (button-exit-action)
* gnu/installer/newt/services.scm (run-desktop-environments-cbt-page,
run-networking-cbt-page, run-other-services-cbt-page,
run-network-management-page)
* gnu/installer/newt/timezone.scm (run-timezone-page)
* gnu/installer/newt/user.scm (run-user-page)
* gnu/installer/newt/welcome.scm (run-menu-page)
* gnu/installer/newt/wifi.scm (run-wifi-page): Use the 'installer-step
prompt to abort.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
4424ba7498 installer: Add nano to PATH.
* gnu/installer.scm (installer-program): Add nano to the installer
PATH.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
7e743738c7 installer: Replace run-command by invoke in newt/page.scm.
* gnu/installer/newt/page.scm (edit-file): Replace it.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
dd5177a377 installer: Fix run-file-textbox-page when edit-button is #f.
* gnu/installer/newt/page.scm (run-file-textbox-page): Check if
edit-button is #f.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
e91ddc728c installer: Raise condition when mklabel fails.
* gnu/installer/parted.scm (mklabel): Do it.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
a7052e84ed installer: Use run-command-in-installer in (gnu installer parted).
* gnu/installer/parted.scm (remove-logical-devices,
create-btrfs-file-system, create-ext4-file-system,
create-fat16-file-system, create-fat32-file-system,
create-jfs-file-system, create-ntfs-file-system,
create-xfs-file-system, create-swap-partition, luks-format-and-open,
luks-close): Use run-command-in-installer.
(with-null-output-ports): Remove.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
917e94b29f installer: Add installer-specific run command process.
* gnu/installer/record.scm (installer)[run-command]: Add field.
* gnu/installer/utils.scm (run-command-in-installer): Add parameter.
* gnu/installer.scm (installer-program): Parameterize
run-command-in-installer with current installer's run-command.
* gnu/installer/newt.scm (newt-run-command): New variable.
(newt-installer): Use it.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:40 +01:00
Josselin Poiret
6494a5493a installer: Capture external commands output.
* gnu/installer/utils.scm (run-external-command-with-handler,
run-external-command-with-line-hooks): New variables.
(run-command): Use run-external-command-with-line-hooks.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:44:39 +01:00
Josselin Poiret
d2d7fcf564 installer: Remove specific logging code.
* gnu/installer/final.scm (install-system): Remove command logging to
syslog, as this is taken care of by the new facilities.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:27:22 +01:00
Josselin Poiret
946420276f installer: Keep PATH inside the install container.
* gnu/installer/final.scm (install-system): Set PATH inside the
container.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:27:22 +01:00
Josselin Poiret
8ee099abe0 installer: Un-export syslog syntax.
* gnu/installer/utils.scm (syslog): Remove export.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:27:22 +01:00
Josselin Poiret
750a0669eb installer: Use new installer-log-line everywhere.
* gnu/installer.scm (installer-program)
* gnu/installer/final.scm (install-locale)
* gnu/installer/newt.scm (init)
* gnu/installer/newt/final.scm (run-final-page)
* gnu/installer/newt/page.scm (run-form-with-clients)
* gnu/installer/newt/partition.scm (run-partitioning-page)
* gnu/installer/parted.scm (eligible-devices, mkpart,
luks-format-and-open, luks-close, mount-user-partitions,
umount-user-partitions, free-parted):
* gnu/installer/steps.scm (run-installer-steps):
* gnu/installer/utils.scm (run-command, send-to-clients): Use it.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:27:22 +01:00
Josselin Poiret
ac014ddd33 installer: Generalize logging facility.
* gnu/installer/utils.scm (%syslog-line-hook, open-new-log-port,
installer-log-port, %installer-log-line-hook, %display-line-hook,
%default-installer-line-hooks, installer-log-line): Add new
variables.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:27:22 +01:00
Josselin Poiret
76c27a5792 installer: Use define instead of let at top-level.
* gnu/installer.scm (installer-program): Improve readability by using
define at top-level.

Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
2022-01-17 08:27:22 +01:00
Mathieu Othacehe
84d0d8ad3d installer: Add crash dump upload support.
Suggested-by: Josselin Poiret <dev@jpoiret.xyz>

* gnu/installer/dump.scm: New file.
* gnu/installer/newt/dump.scm: New file.
* gnu/local.mk (INSTALLER_MODULES): Add them.
* gnu/installer/record.scm (<installer>)[dump-page]: New field.
* gnu/installer/steps.scm (%current-result): New variable.
(run-installer-steps): Update it.
* gnu/installer.scm (installer-program): Add tar and gip to the installer
path. Add guile-webutils and gnutls to the Guile extensions. Generate and send
the crash dump report.
* gnu/installer/newt.scm (exit-error): Add a report argument. Display the
report id.
(dump-page): New procedure.
(newt-installer): Update it.
2022-01-14 14:32:12 +01:00
22 changed files with 756 additions and 315 deletions

View File

@@ -33,6 +33,7 @@
#:use-module (gnu packages admin)
#:use-module (gnu packages base)
#:use-module (gnu packages bash)
#:use-module (gnu packages compression)
#:use-module (gnu packages connman)
#:use-module (gnu packages cryptsetup)
#:use-module (gnu packages disk)
@@ -42,6 +43,7 @@
#:autoload (gnu packages gnupg) (guile-gcrypt)
#:use-module (gnu packages iso-codes)
#:use-module (gnu packages linux)
#:use-module (gnu packages nano)
#:use-module (gnu packages ncurses)
#:use-module (gnu packages package-management)
#:use-module (gnu packages tls)
@@ -333,9 +335,11 @@ selected keymap."
ntfs-3g ;mkfs.ntfs
xfsprogs ;mkfs.xfs
kbd ;chvt
guix ;guix system init call
util-linux ;mkwap
nano
shadow
tar ;dump
gzip ;dump
coreutils)))
(with-output-to-port (%make-void-port "w")
(lambda ()
@@ -352,7 +356,8 @@ selected keymap."
;; packages …), etc. modules.
(with-extensions (list guile-gcrypt guile-newt
guile-parted guile-bytestructures
guile-json-3 guile-git guix gnutls)
guile-json-3 guile-git guile-webutils
guix gnutls)
(with-imported-modules `(,@(source-module-closure
`(,@modules
(gnu services herd)
@@ -363,6 +368,7 @@ selected keymap."
(use-modules (gnu installer record)
(gnu installer keymap)
(gnu installer steps)
(gnu installer dump)
(gnu installer final)
(gnu installer hostname)
(gnu installer locale)
@@ -379,7 +385,8 @@ selected keymap."
(guix build utils)
((system repl debug)
#:select (terminal-width))
(ice-9 match))
(ice-9 match)
(ice-9 textual-ports))
;; Initialize gettext support so that installers can use
;; (guix i18n) module.
@@ -407,43 +414,56 @@ selected keymap."
;; verbose.
(terminal-width 200)
(let* ((current-installer newt-installer)
(steps (#$steps current-installer)))
((installer-init current-installer))
(define current-installer newt-installer)
(define steps (#$steps current-installer))
(catch #t
(lambda ()
(define results
(run-installer-steps
#:rewind-strategy 'menu
#:menu-proc (installer-menu-page current-installer)
#:steps steps))
(dynamic-wind
(installer-init current-installer)
(lambda ()
(parameterize
((run-command-in-installer
(installer-run-command current-installer)))
(catch #t
(lambda ()
(define results
(run-installer-steps
#:rewind-strategy 'menu
#:menu-proc (installer-menu-page current-installer)
#:steps steps))
(match (result-step results 'final)
('success
;; We did it! Let's reboot!
(sync)
(stop-service 'root))
(_
;; The installation failed, exit so that it is restarted
;; by login.
#f)))
(const #f)
(lambda (key . args)
(syslog "crashing due to uncaught exception: ~s ~s~%"
key args)
(let ((error-file "/tmp/last-installer-error"))
(call-with-output-file error-file
(lambda (port)
(display-backtrace (make-stack #t) port)
(print-exception port
(stack-ref (make-stack #t) 1)
key args)))
((installer-exit-error current-installer)
error-file key args))
(primitive-exit 1)))
(match (result-step results 'final)
('success
;; We did it! Let's reboot!
(sync)
(stop-service 'root))
(_
;; The installation failed, exit so that it is
;; restarted by login.
#f)))
(const #f)
(lambda (key . args)
(installer-log-line "crashing due to uncaught exception: ~s ~s"
key args)
(define dump-dir
(prepare-dump key args #:result %current-result))
(define action
((installer-exit-error current-installer)
(get-string-all
(open-input-file
(string-append dump-dir "/installer-backtrace")))))
(match action
('dump
(let* ((dump-files
((installer-dump-page current-installer)
dump-dir))
(dump-archive
(make-dump dump-dir dump-files)))
((installer-report-page current-installer)
dump-archive)))
(_ #f))
(exit 1)))))
((installer-exit current-installer)))))))
(installer-exit current-installer))))))
(program-file
"installer"

118
gnu/installer/dump.scm Normal file
View File

@@ -0,0 +1,118 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Mathieu Othacehe <othacehe@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu installer dump)
#:use-module (gnu installer utils)
#:use-module (guix build utils)
#:use-module (srfi srfi-11)
#:use-module (ice-9 iconv)
#:use-module (ice-9 match)
#:use-module (ice-9 popen)
#:use-module (ice-9 textual-ports)
#:use-module (web client)
#:use-module (web http)
#:use-module (web response)
#:use-module (webutils multipart)
#:export (prepare-dump
make-dump
send-dump-report))
;; The installer crash dump type.
(define %dump-type "installer-dump")
(define (result->list result)
"Return the alist for the given RESULT."
(hash-map->list (lambda (k v)
(cons k v))
result))
(define* (prepare-dump key args #:key result)
"Create a crash dump directory. KEY and ARGS represent the thrown error.
RESULT is the installer result hash table. Returns the created directory path."
(define now (localtime (current-time)))
(define dump-dir
(format #f "/tmp/dump.~a"
(strftime "%F.%H.%M.%S" now)))
(mkdir-p dump-dir)
(with-directory-excursion dump-dir
;; backtrace
(call-with-output-file "installer-backtrace"
(lambda (port)
(display-backtrace (make-stack #t) port)
(print-exception port
(stack-ref (make-stack #t) 1)
key args)))
;; installer result
(call-with-output-file "installer-result"
(lambda (port)
(write (result->list result) port)))
;; syslog
(copy-file "/var/log/messages" "syslog")
;; dmesg
(let ((pipe (open-pipe* OPEN_READ "dmesg")))
(call-with-output-file "dmesg"
(lambda (port)
(dump-port pipe port)
(close-pipe pipe)))))
dump-dir)
(define* (make-dump dump-dir file-choices)
"Create a crash dump archive from DUMP-DIR containing FILE-CHOICES.
Returns the archive path."
(define output (string-append (basename dump-dir) ".tar.gz"))
(with-directory-excursion (dirname dump-dir)
(apply system* "tar" "-zcf" output
(map (lambda (f)
(string-append (basename dump-dir) "/" f))
file-choices)))
(canonicalize-path (string-append (dirname dump-dir) "/" output)))
(define* (send-dump-report dump
#:key
(url "https://dump.guix.gnu.org"))
"Turn the DUMP archive into a multipart body and send it to the Guix crash
dump server at URL."
(define (match-boundary kont)
(match-lambda
(('boundary . (? string? b))
(kont b))
(x #f)))
(define (response->string response)
(bytevector->string
(read-response-body response)
"UTF-8"))
(let-values (((body boundary)
(call-with-input-file dump
(lambda (port)
(format-multipart-body
`((,%dump-type . ,port)))))))
(false-if-exception
(response->string
(http-post
(string-append url "/upload")
#:keep-alive? #t
#:streaming? #t
#:headers `((content-type
. (multipart/form-data
(boundary . ,boundary))))
#:body body)))))

View File

@@ -85,8 +85,9 @@ USERS."
(uid (if root? 0 #f))
(home-directory
(user-home-directory user))
(password (crypt (user-password user)
(salt)))
(password (crypt
(secret-content (user-password user))
(salt)))
;; We need a string here, not a file-like, hence
;; this choice.
@@ -125,15 +126,15 @@ it can interact with the rest of the system."
(setlocale LC_ALL locale))))
(if supported?
(begin
(syslog "install supported locale ~a~%." locale)
(installer-log-line "install supported locale ~a." locale)
(setenv "LC_ALL" locale))
(begin
;; If the selected locale is not supported, install a default UTF-8
;; locale. This is required to copy some files with UTF-8
;; characters, in the nss-certs package notably. Set LANGUAGE
;; anyways, to have translated messages if possible.
(syslog "~a locale is not supported, installating en_US.utf8 \
locale instead.~%" locale)
(installer-log-line "~a locale is not supported, installing \
en_US.utf8 locale instead." locale)
(setlocale LC_ALL "en_US.utf8")
(setenv "LC_ALL" "en_US.utf8")
(setenv "LANGUAGE"
@@ -208,17 +209,9 @@ or #f. Return #t on success and #f on failure."
(setvbuf (current-output-port) 'none)
(setvbuf (current-error-port) 'none)
;; If there are any connected clients, assume that we are running
;; installation tests. In that case, dump the standard and error
;; outputs to syslog.
(set! ret
(if (not (null? (current-clients)))
(with-output-to-file "/dev/console"
(lambda ()
(with-error-to-file "/dev/console"
(lambda ()
(run-command install-command)))))
(run-command install-command))))
(setenv "PATH" "/run/current-system/profile/bin/")
(set! ret (run-command install-command)))
(lambda ()
;; Restart guix-daemon so that it does no keep the MNT namespace
;; alive.

View File

@@ -19,6 +19,7 @@
(define-module (gnu installer newt)
#:use-module (gnu installer record)
#:use-module (gnu installer utils)
#:use-module (gnu installer dump)
#:use-module (gnu installer newt ethernet)
#:use-module (gnu installer newt final)
#:use-module (gnu installer newt parameters)
@@ -39,7 +40,12 @@
#:use-module (guix config)
#:use-module (guix discovery)
#:use-module (guix i18n)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#:use-module (ice-9 ftw)
#:use-module (ice-9 match)
#:use-module (newt)
#:export (newt-installer))
@@ -47,7 +53,7 @@
(newt-init)
(clear-screen)
(set-screen-size!)
(syslog "Display is ~ax~a.~%" (screen-columns) (screen-rows))
(installer-log-line "Display is ~ax~a." (screen-columns) (screen-rows))
(push-help-line
(format #f (G_ "Press <F1> for installation parameters."))))
@@ -55,25 +61,102 @@
(newt-finish)
(clear-screen))
(define (exit-error file key args)
(define (exit-error error)
(newt-set-color COLORSET-ROOT "white" "red")
(let ((width (nearest-exact-integer
(* (screen-columns) 0.8)))
(height (nearest-exact-integer
(* (screen-rows) 0.7))))
(run-file-textbox-page
#:info-text (format #f (G_ "The installer has encountered an unexpected \
problem. The backtrace is displayed below. Please report it by email to \
<~a>.") %guix-bug-report-address)
(define action
(run-textbox-page
#:info-text (G_ "The installer has encountered an unexpected problem. \
The backtrace is displayed below. You may choose to exit or create a dump \
archive.")
#:title (G_ "Unexpected problem")
#:file file
#:exit-button? #f
#:info-textbox-width width
#:file-textbox-width width
#:file-textbox-height height))
#:content error
#:buttons-spec
(list
(cons (G_ "Dump") (const 'dump))
(cons (G_ "Exit") (const 'exit)))))
(newt-set-color COLORSET-ROOT "white" "blue")
(newt-finish)
(clear-screen))
action)
(define (report-page dump-archive)
(define text
(format #f (G_ "The dump archive was created as ~a. Would you like to \
send this archive to the Guix servers?") dump-archive))
(define title (G_ "Dump archive created"))
(when (run-confirmation-page text title)
(let* ((uploaded-name (send-dump-report dump-archive))
(text (if uploaded-name
(format #f (G_ "The dump was uploaded as ~a. Please \
report it by email to ~a.") uploaded-name %guix-bug-report-address)
(G_ "The dump could not be uploaded."))))
(run-error-page
text
(G_ "Dump upload result")))))
(define (dump-page dump-dir)
(define files
(scandir dump-dir (lambda (x)
(not (or (string=? x ".")
(string=? x ".."))))))
(fold (match-lambda*
(((file . enable?) acc)
(if enable?
(cons file acc)
acc)))
'()
(run-dump-page
dump-dir
(map (lambda (x)
(cons x #f))
files))))
(define (newt-run-command . args)
(define command-output "")
(define (line-accumulator line)
(set! command-output
(string-append/shared command-output line "\n")))
(define displayed-command
(string-join
(map (lambda (s) (string-append "\"" s "\"")) args)
" "))
(define result (run-external-command-with-line-hooks (list line-accumulator)
args))
(define exit-val (status:exit-val result))
(define term-sig (status:term-sig result))
(define stop-sig (status:stop-sig result))
(if (and exit-val (zero? exit-val))
#t
(let ((info-text
(cond
(exit-val
(format #f (G_ "External command ~s exited with code ~a")
args exit-val))
(term-sig
(format #f (G_ "External command ~s terminated by signal ~a")
args term-sig))
(stop-sig
(format #f (G_ "External command ~s stopped by signal ~a")
args stop-sig)))))
(run-textbox-page #:title (G_ "External command error")
#:info-text info-text
#:content command-output
#:buttons-spec
(list
(cons "Ignore" (const #t))
(cons "Abort"
(lambda ()
(abort-to-prompt 'installer-step 'abort)))
(cons "Report"
(lambda ()
(raise
(condition
((@@ (guix build utils)
&invoke-error)
(program (car args))
(arguments (cdr args))
(exit-status exit-val)
(term-signal term-sig)
(stop-signal stop-sig)))))))))))
(define (final-page result prev-steps)
(run-final-page result prev-steps))
@@ -142,4 +225,7 @@ problem. The backtrace is displayed below. Please report it by email to \
(services-page services-page)
(welcome-page welcome-page)
(parameters-menu parameters-menu)
(parameters-page parameters-page)))
(parameters-page parameters-page)
(dump-page dump-page)
(run-command newt-run-command)
(report-page report-page)))

View File

@@ -65,9 +65,7 @@ connection is pending."
(run-error-page
(G_ "No ethernet service available, please try again.")
(G_ "No service"))
(raise
(condition
(&installer-step-abort))))
(abort-to-prompt 'installer-step 'abort))
((service)
;; Only one service is available so return it directly.
service)
@@ -81,7 +79,5 @@ connection is pending."
#:button-text (G_ "Exit")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort))))
(abort-to-prompt 'installer-step 'abort))
#:listbox-callback-procedure connect-ethernet-service))))

View File

@@ -59,9 +59,7 @@ This will take a few minutes.")
#:file-textbox-height height
#:exit-button-callback-procedure
(lambda ()
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (run-install-success-page)
(match (current-clients)
@@ -88,9 +86,7 @@ press the button to reboot.")))
(G_ "Restart the installer")
(G_ "The final system installation step failed. You can resume from \
a specific step, or restart the installer."))
(1 (raise
(condition
(&installer-step-abort))))
(1 (abort-to-prompt 'installer-step 'abort))
(2
;; Keep going, the installer will be restarted later on.
#t)))
@@ -109,7 +105,7 @@ a specific step, or restart the installer."))
(define (run-final-page result prev-steps)
(define (wait-for-clients)
(unless (null? (current-clients))
(syslog "waiting with clients before starting final step~%")
(installer-log-line "waiting with clients before starting final step")
(send-to-clients '(starting-final-step))
(match (select (current-clients) '() '())
(((port _ ...) _ _)
@@ -119,7 +115,7 @@ a specific step, or restart the installer."))
;; things such as changing the swap partition label.
(wait-for-clients)
(syslog "proceeding with final step~%")
(installer-log-line "proceeding with final step")
(let* ((configuration (format-configuration prev-steps result))
(user-partitions (result-step result 'partition))
(locale (result-step result 'locale))

View File

@@ -59,9 +59,7 @@ different layout at any time from the parameters menu.")))
((param) (const #f))
(else
(lambda _
(raise
(condition
(&installer-step-abort)))))))))
(abort-to-prompt 'installer-step 'abort)))))))
(define (run-variant-page variants variant->text)
(let ((title (G_ "Variant")))
@@ -74,9 +72,7 @@ different layout at any time from the parameters menu.")))
#:button-text (G_ "Back")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (sort-layouts layouts)
"Sort LAYOUTS list by putting the US layout ahead and return it."

View File

@@ -43,9 +43,7 @@ installation process and for the installed system.")
#:button-text (G_ "Exit")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort))))))
(abort-to-prompt 'installer-step 'abort))))
;; Immediately install the chosen language so that the territory page that
;; comes after (optionally) is displayed in the chosen language.
@@ -63,9 +61,7 @@ installation process and for the installed system.")
#:button-text (G_ "Back")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (run-codeset-page codesets)
(let ((title (G_ "Locale codeset")))
@@ -78,9 +74,7 @@ installation process and for the installed system.")
#:button-text (G_ "Back")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (run-modifier-page modifiers modifier->text)
(let ((title (G_ "Locale modifier")))
@@ -94,9 +88,7 @@ symbol.")
#:button-text (G_ "Back")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define* (run-locale-page #:key
supported-locales
@@ -110,11 +102,10 @@ associating a territory code with a territory name. The formatted locale, under
glibc format is returned."
(define (break-on-locale-found locales)
"Raise the &installer-step-break condition if LOCALES contains exactly one
"Break to the installer step if LOCALES contains exactly one
element."
(and (= (length locales) 1)
(raise
(condition (&installer-step-break)))))
(abort-to-prompt 'installer-step 'break)))
(define (filter-locales locales result)
"Filter the list of locale records LOCALES using the RESULT returned by
@@ -218,8 +209,8 @@ glibc locale string and return it."
;; If run-installer-steps returns locally, it means that the user had to go
;; through all steps (language, territory, codeset and modifier) to select a
;; locale. In that case, like if we exited by raising &installer-step-break
;; condition, turn the result into a glibc locale string and return it.
;; locale. In that case, like if we exited by breaking to the installer
;; step, turn the result into a glibc locale string and return it.
(result->locale-string
supported-locales
(run-installer-steps #:steps locale-steps)))

View File

@@ -65,12 +65,8 @@ Internet and return the selected technology. For now, only technologies with
(G_ "Exit")
(G_ "The install process requires Internet access but no \
network devices were found. Do you want to continue anyway?"))
((1) (raise
(condition
(&installer-step-break))))
((2) (raise
(condition
(&installer-step-abort))))))
((1) (abort-to-prompt 'installer-step 'break))
((2) (abort-to-prompt 'installer-step 'abort))))
((technology)
;; Since there's only one technology available, skip the selection
;; screen.
@@ -86,9 +82,7 @@ network devices were found. Do you want to continue anyway?"))
#:button-text (G_ "Exit")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort))))))))
(abort-to-prompt 'installer-step 'abort))))))
(define (find-technology-by-type technologies type)
"Find and return a technology with the given TYPE in TECHNOLOGIES list."
@@ -156,9 +150,7 @@ FULL-VALUE tentatives, spaced by 1 second."
(G_ "The selected network does not provide access to the \
Internet and the Guix substitute server, please try again.")
(G_ "Connection error"))
(raise
(condition
(&installer-step-abort))))))
(abort-to-prompt 'installer-step 'abort))))
(define (run-network-page)
"Run a page to allow the user to configure connman so that it can access the

View File

@@ -22,6 +22,7 @@
#:use-module (gnu installer steps)
#:use-module (gnu installer utils)
#:use-module (gnu installer newt utils)
#:use-module (guix build utils)
#:use-module (guix i18n)
#:use-module (ice-9 i18n)
#:use-module (ice-9 match)
@@ -43,6 +44,10 @@
run-scale-page
run-checkbox-tree-page
run-file-textbox-page
%ok-button
%exit-button
run-textbox-page
run-dump-page
run-form-with-clients))
@@ -93,9 +98,9 @@ disconnect.
Like 'run-form', return two values: the exit reason, and an \"argument\"."
(define* (discard-client! port #:optional errno)
(if errno
(syslog "removing client ~d due to ~s~%"
(installer-log-line "removing client ~d due to ~s"
(fileno port) (strerror errno))
(syslog "removing client ~d due to EOF~%"
(installer-log-line "removing client ~d due to EOF"
(fileno port)))
;; XXX: Watch out! There's no 'form-unwatch-fd' procedure in Newt so we
@@ -124,7 +129,7 @@ Like 'run-form', return two values: the exit reason, and an \"argument\"."
(send-to-clients exp)
(let loop ()
(syslog "running form ~s (~s) with ~d clients~%"
(installer-log-line "running form ~s (~s) with ~d clients"
form title (length (current-clients)))
;; Call 'watch-clients!' within the loop because there might be new
@@ -146,7 +151,7 @@ Like 'run-form', return two values: the exit reason, and an \"argument\"."
(discard-client! port)
(loop))
(obj
(syslog "form ~s (~s): client ~d replied ~s~%"
(installer-log-line "form ~s (~s): client ~d replied ~s"
form title (fileno port) obj)
(values 'exit-fd-ready obj))))
(lambda args
@@ -156,8 +161,9 @@ Like 'run-form', return two values: the exit reason, and an \"argument\"."
;; Accept a new client and send it EXP.
(match (accept port)
((client . _)
(syslog "accepting new client ~d while on form ~s~%"
(fileno client) form)
(installer-log-line
"accepting new client ~d while on form ~s"
(fileno client) form)
(catch 'system-error
(lambda ()
(write exp client)
@@ -486,7 +492,7 @@ the current listbox item has to be selected by key."
(string=? str (listbox-item->text item))))
keys)
((key . item) item)
(#f (raise (condition (&installer-step-abort))))))
(#f (abort-to-prompt 'installer-step 'abort))))
;; On every listbox element change, check if we need to skip it. If yes,
;; depending on the 'last-listbox-key', jump forward or backward. If no,
@@ -688,7 +694,7 @@ ITEMS when 'Ok' is pressed."
(string=? str (item->text item))))
keys)
((key . item) item)
(#f (raise (condition (&installer-step-abort))))))
(#f (abort-to-prompt 'installer-step 'abort))))
(add-form-to-grid grid form #t)
(make-wrapped-grid-window grid title)
@@ -726,8 +732,7 @@ ITEMS when 'Ok' is pressed."
(newt-suspend)
;; Use Nano because it syntax-highlights Scheme by default.
;; TODO: Add a menu to choose an editor?
(run-command (list "/run/current-system/profile/bin/nano" file)
#:locale locale)
(invoke "nano" file)
(newt-resume))
(define* (run-file-textbox-page #:key
@@ -811,6 +816,151 @@ ITEMS when 'Ok' is pressed."
(destroy-form-and-pop form))))
(if (and (eq? exit-reason 'exit-component)
edit-button
(components=? argument edit-button))
(loop) ;recurse in tail position
result)))))
(define %ok-button
(cons (G_ "Ok") (lambda () #t)))
(define %exit-button
(cons (G_ "Exit") (lambda () (abort-to-prompt 'installer-step 'abort))))
(define %default-buttons
(list %ok-button %exit-button))
(define (make-newt-buttons buttons-spec)
(map
(match-lambda ((title . proc)
(cons (make-button -1 -1 title) proc)))
buttons-spec))
(define* (run-textbox-page #:key
title
info-text
content
(buttons-spec %default-buttons))
"Run a page to display INFO-TEXT followed by CONTENT to the user, who has to
choose an action among the buttons specified by BUTTONS-SPEC.
BUTTONS-SPEC is an association list with button labels as keys, and callback
procedures as values.
This procedure returns the result of the callback procedure of the button
chosen by the user."
(define info-textbox
(make-reflowed-textbox -1 -1 info-text
50
#:flags FLAG-BORDER))
(define content-textbox
(make-textbox -1 -1
50
30
(logior FLAG-SCROLL FLAG-BORDER)))
(define buttons
(make-newt-buttons buttons-spec))
(define grid
(vertically-stacked-grid
GRID-ELEMENT-COMPONENT info-textbox
GRID-ELEMENT-COMPONENT content-textbox
GRID-ELEMENT-SUBGRID
(apply
horizontal-stacked-grid
(append-map (match-lambda ((button . proc)
(list GRID-ELEMENT-COMPONENT button)))
buttons))))
(define form (make-form #:flags FLAG-NOF12))
(add-form-to-grid grid form #t)
(make-wrapped-grid-window grid title)
(set-textbox-text content-textbox
(receive (_w _h text)
(reflow-text content
50
0 0)
text))
(receive (exit-reason argument)
(run-form-with-clients form
`(contents-dialog (title ,title)
(text ,info-text)
(content ,content)))
(destroy-form-and-pop form)
(match exit-reason
('exit-component
(let ((proc (assq-ref buttons argument)))
(if proc
(proc)
(raise
(condition
(&serious)
(&message
(message (format #f "Unable to find corresponding PROC for \
component ~a." argument))))))))
;; TODO
('exit-fd-ready
(raise (condition (&serious)))))))
(define* (run-dump-page base-dir file-choices)
(define info-textbox
(make-reflowed-textbox -1 -1 "Please select files you wish to include in \
the dump."
50
#:flags FLAG-BORDER))
(define components
(map (match-lambda ((file . enabled)
(list
(make-compact-button -1 -1 "Edit")
(make-checkbox -1 -1 file (if enabled #\x #\ ) " x")
file)))
file-choices))
(define sub-grid (make-grid 2 (length components)))
(for-each
(match-lambda* (((button checkbox _) index)
(set-grid-field sub-grid 0 index
GRID-ELEMENT-COMPONENT checkbox
#:anchor ANCHOR-LEFT)
(set-grid-field sub-grid 1 index
GRID-ELEMENT-COMPONENT button
#:anchor ANCHOR-LEFT)))
components (iota (length components)))
(define grid
(vertically-stacked-grid
GRID-ELEMENT-COMPONENT info-textbox
GRID-ELEMENT-SUBGRID sub-grid
GRID-ELEMENT-COMPONENT (make-button -1 -1 "Create")))
(define form (make-form #:flags FLAG-NOF12))
(add-form-to-grid grid form #t)
(make-wrapped-grid-window grid "Installer dump")
(define prompt-tag (make-prompt-tag))
(let loop ()
(call-with-prompt prompt-tag
(lambda ()
(receive (exit-reason argument)
(run-form-with-clients form
`(dump-page))
(match exit-reason
('exit-component
(let ((result
(map (match-lambda
((edit checkbox filename)
(if (components=? edit argument)
(abort-to-prompt prompt-tag filename)
(cons filename (eq? #\x
(checkbox-value checkbox))))))
components)))
(destroy-form-and-pop form)
result))
;; TODO
('exit-fd-ready
(raise (condition (&serious)))))))
(lambda (k file)
(edit-file (string-append base-dir "/" file))
(loop)))))

View File

@@ -36,10 +36,8 @@
#:export (run-partitioning-page))
(define (button-exit-action)
"Raise the &installer-step-abort condition."
(raise
(condition
(&installer-step-abort))))
"Abort the installer step."
(abort-to-prompt 'installer-step 'abort))
(define (run-scheme-page)
"Run a page asking the user for a partitioning scheme."
@@ -801,9 +799,9 @@ by pressing the Exit button.~%~%")))
;; Make sure the disks are not in use before proceeding to formatting.
(free-parted eligible-devices)
(format-user-partitions user-partitions-with-pass)
(syslog "formatted ~a user partitions~%"
(installer-log-line "formatted ~a user partitions"
(length user-partitions-with-pass))
(syslog "user-partitions: ~a~%" user-partitions)
(installer-log-line "user-partitions: ~a" user-partitions)
(destroy-form-and-pop form)
user-partitions))

View File

@@ -46,9 +46,7 @@ to choose from them later when you log in.")
#:checkbox-tree-height 9
#:exit-button-callback-procedure
(lambda ()
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (run-networking-cbt-page)
"Run a page allowing the user to select networking services."
@@ -65,9 +63,7 @@ system.")
#:checkbox-tree-height 5
#:exit-button-callback-procedure
(lambda ()
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (run-printing-services-cbt-page)
"Run a page allowing the user to select document services such as CUPS."
@@ -85,9 +81,7 @@ system.")
#:checkbox-tree-height 9
#:exit-button-callback-procedure
(lambda ()
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (run-console-services-cbt-page)
"Run a page to select various system adminstration services for non-graphical
@@ -130,9 +124,7 @@ client may be enough for a server.")
#:button-text (G_ "Exit")
#:button-callback-procedure
(lambda _
(raise
(condition
(&installer-step-abort)))))))
(abort-to-prompt 'installer-step 'abort)))))
(define (run-services-page)
(let ((desktop (run-desktop-environments-cbt-page)))

View File

@@ -65,9 +65,7 @@ returned."
#:button-callback-procedure
(if (null? path)
(lambda _
(raise
(condition
(&installer-step-abort))))
(abort-to-prompt 'installer-step 'abort))
(lambda _
(loop (all-but-last path))))
#:listbox-callback-procedure

View File

@@ -20,7 +20,6 @@
(define-module (gnu installer newt user)
#:use-module (gnu installer user)
#:use-module ((gnu installer steps) #:select (&installer-step-abort))
#:use-module (gnu installer newt page)
#:use-module (gnu installer newt utils)
#:use-module (gnu installer utils)
@@ -144,7 +143,7 @@ REAL-NAME, and HOME-DIRECTORY as the initial values in the form."
(name name)
(real-name real-name)
(home-directory home-directory)
(password password))
(password (make-secret password)))
(run-user-add-page #:name name
#:real-name real-name
#:home-directory
@@ -257,9 +256,7 @@ administrator (\"root\").")
(run users))
(reverse users))
((components=? argument exit-button)
(raise
(condition
(&installer-step-abort))))))
(abort-to-prompt 'installer-step 'abort))))
('exit-fd-ready
;; Read the complete user list at once.
(match argument
@@ -269,7 +266,7 @@ administrator (\"root\").")
(map (lambda (name real-name home password)
(user (name name) (real-name real-name)
(home-directory home)
(password password)))
(password (make-secret password))))
names real-names homes passwords))))))
(lambda ()
(destroy-form-and-pop form))))))
@@ -277,5 +274,5 @@ administrator (\"root\").")
;; Add a "root" user simply to convey the root password.
(cons (user (name "root")
(home-directory "/root")
(password (run-root-password-page)))
(password (make-secret (run-root-password-page))))
(run '())))

View File

@@ -84,7 +84,7 @@ we want this page to occupy all the screen space available."
(string=? str (listbox-item->text item))))
keys)
((key . item) item)
(#f (raise (condition (&installer-step-abort))))))
(#f (abort-to-prompt 'installer-step 'abort))))
(set-textbox-text logo-textbox (read-all logo))

View File

@@ -237,9 +237,7 @@ force a wifi scan."
(run-wifi-scan-page)
(run-wifi-page))
((components=? argument exit-button)
(raise
(condition
(&installer-step-abort))))
(abort-to-prompt 'installer-step 'abort))
((components=? argument listbox)
(let ((result (connect-wifi-service listbox service-items)))
(unless result

View File

@@ -343,8 +343,7 @@ fail. See rereadpt function in wipefs.c of util-linux for an explanation."
(define (remove-logical-devices)
"Remove all active logical devices."
(with-null-output-ports
(invoke "dmsetup" "remove_all")))
((run-command-in-installer) "dmsetup" "remove_all"))
(define (installer-root-partition-path)
"Return the root partition path, or #f if it could not be detected."
@@ -371,7 +370,8 @@ which are smaller than %MIN-DEVICE-SIZE."
(let ((length (device-length device))
(sector-size (device-sector-size device)))
(and (< (* length sector-size) %min-device-size)
(syslog "~a is not eligible because it is smaller than ~a.~%"
(installer-log-line "~a is not eligible because it is smaller than \
~a."
(device-path device)
(unit-format-custom-byte device
%min-device-size
@@ -391,7 +391,8 @@ which are smaller than %MIN-DEVICE-SIZE."
(string=? the-installer-root-partition-path
(partition-get-path partition)))
(disk-partitions disk)))))
(syslog "~a is not eligible because it is the installation device.~%"
(installer-log-line "~a is not eligible because it is the \
installation device."
(device-path device))))
(remove
@@ -634,8 +635,14 @@ determined by MAX-LENGTH-COLUMN procedure."
(define (mklabel device type-name)
"Create a partition table on DEVICE. TYPE-NAME is the type of the partition
table, \"msdos\" or \"gpt\"."
(let ((type (disk-type-get type-name)))
(disk-new-fresh device type)))
(let* ((type (disk-type-get type-name))
(disk (disk-new-fresh device type)))
(or disk
(raise
(condition
(&error)
(&message (message (format #f "Cannot create partition table of type
~a on device ~a." type-name (device-path device)))))))))
;;
@@ -817,24 +824,22 @@ cause them to cross."
(disk-add-partition disk partition no-constraint)))
(partition-ok?
(or partition-constraint-ok? partition-no-contraint-ok?)))
(syslog "Creating partition:
~/type: ~a
~/filesystem-type: ~a
~/start: ~a
~/end: ~a
~/start-range: [~a, ~a]
~/end-range: [~a, ~a]
~/constraint: ~a
~/no-constraint: ~a
"
partition-type
(filesystem-type-name filesystem-type)
start-sector*
end-sector
(geometry-start start-range) (geometry-end start-range)
(geometry-start end-range) (geometry-end end-range)
partition-constraint-ok?
partition-no-contraint-ok?)
(installer-log-line "Creating partition:")
(installer-log-line "~/type: ~a" partition-type)
(installer-log-line "~/filesystem-type: ~a"
(filesystem-type-name filesystem-type))
(installer-log-line "~/start: ~a" start-sector*)
(installer-log-line "~/end: ~a" end-sector)
(installer-log-line "~/start-range: [~a, ~a]"
(geometry-start start-range)
(geometry-end start-range))
(installer-log-line "~/end-range: [~a, ~a]"
(geometry-start end-range)
(geometry-end end-range))
(installer-log-line "~/constraint: ~a"
partition-constraint-ok?)
(installer-log-line "~/no-constraint: ~a"
partition-no-contraint-ok?)
;; Set the partition name if supported.
(when (and partition-ok? has-name? name)
(partition-set-name partition name))
@@ -1115,53 +1120,37 @@ list and return the updated list."
(file-name file-name))))
user-partitions))
(define-syntax-rule (with-null-output-ports exp ...)
"Evaluate EXP with both the output port and the error port pointing to the
bit bucket."
(with-output-to-port (%make-void-port "w")
(lambda ()
(with-error-to-port (%make-void-port "w")
(lambda () exp ...)))))
(define (create-btrfs-file-system partition)
"Create a btrfs file-system for PARTITION file-name."
(with-null-output-ports
(invoke "mkfs.btrfs" "-f" partition)))
((run-command-in-installer) "mkfs.btrfs" "-f" partition))
(define (create-ext4-file-system partition)
"Create an ext4 file-system for PARTITION file-name."
(with-null-output-ports
(invoke "mkfs.ext4" "-F" partition)))
((run-command-in-installer) "mkfs.ext4" "-F" partition))
(define (create-fat16-file-system partition)
"Create a fat16 file-system for PARTITION file-name."
(with-null-output-ports
(invoke "mkfs.fat" "-F16" partition)))
((run-command-in-installer) "mkfs.fat" "-F16" partition))
(define (create-fat32-file-system partition)
"Create a fat32 file-system for PARTITION file-name."
(with-null-output-ports
(invoke "mkfs.fat" "-F32" partition)))
((run-command-in-installer) "mkfs.fat" "-F32" partition))
(define (create-jfs-file-system partition)
"Create a JFS file-system for PARTITION file-name."
(with-null-output-ports
(invoke "jfs_mkfs" "-f" partition)))
((run-command-in-installer) "jfs_mkfs" "-f" partition))
(define (create-ntfs-file-system partition)
"Create a JFS file-system for PARTITION file-name."
(with-null-output-ports
(invoke "mkfs.ntfs" "-F" "-f" partition)))
((run-command-in-installer) "mkfs.ntfs" "-F" "-f" partition))
(define (create-xfs-file-system partition)
"Create an XFS file-system for PARTITION file-name."
(with-null-output-ports
(invoke "mkfs.xfs" "-f" partition)))
((run-command-in-installer) "mkfs.xfs" "-f" partition))
(define (create-swap-partition partition)
"Set up swap area on PARTITION file-name."
(with-null-output-ports
(invoke "mkswap" "-f" partition)))
((run-command-in-installer) "mkswap" "-f" partition))
(define (call-with-luks-key-file password proc)
"Write PASSWORD in a temporary file and pass it to PROC as argument."
@@ -1188,17 +1177,18 @@ USER-PARTITION if it is encrypted, or the plain file-name otherwise."
(call-with-luks-key-file
password
(lambda (key-file)
(syslog "formatting and opening LUKS entry ~s at ~s~%"
(installer-log-line "formatting and opening LUKS entry ~s at ~s"
label file-name)
(system* "cryptsetup" "-q" "luksFormat" file-name key-file)
(system* "cryptsetup" "open" "--type" "luks"
"--key-file" key-file file-name label)))))
((run-command-in-installer) "cryptsetup" "-q" "luksFormat"
file-name key-file)
((run-command-in-installer) "cryptsetup" "open" "--type" "luks"
"--key-file" key-file file-name label)))))
(define (luks-close user-partition)
"Close the encrypted partition pointed by USER-PARTITION."
(let ((label (user-partition-crypt-label user-partition)))
(syslog "closing LUKS entry ~s~%" label)
(system* "cryptsetup" "close" label)))
(installer-log-line "closing LUKS entry ~s" label)
((run-command-in-installer) "cryptsetup" "close" label)))
(define (format-user-partitions user-partitions)
"Format the <user-partition> records in USER-PARTITIONS list with
@@ -1279,7 +1269,7 @@ respective mount-points."
(file-name
(user-partition-upper-file-name user-partition)))
(mkdir-p target)
(syslog "mounting ~s on ~s~%" file-name target)
(installer-log-line "mounting ~s on ~s" file-name target)
(mount file-name target mount-type)))
sorted-partitions)))
@@ -1295,7 +1285,7 @@ respective mount-points."
(target
(string-append (%installer-target-dir)
mount-point)))
(syslog "unmounting ~s~%" target)
(installer-log-line "unmounting ~s" target)
(umount target)
(when crypt-label
(luks-close user-partition))))
@@ -1486,6 +1476,6 @@ the devices not to be used before returning."
(error
(format #f (G_ "Device ~a is still in use.")
file-name))
(syslog "Syncing ~a took ~a seconds.~%"
(installer-log-line "Syncing ~a took ~a seconds."
file-name (time-second time)))))
device-file-names)))

View File

@@ -41,7 +41,10 @@
installer-services-page
installer-welcome-page
installer-parameters-menu
installer-parameters-page))
installer-parameters-page
installer-dump-page
installer-run-command
installer-report-page))
;;;
@@ -61,7 +64,7 @@
(init installer-init)
;; procedure: void -> void
(exit installer-exit)
;; procedure (key arguments) -> void
;; procedure (key arguments) -> (action)
(exit-error installer-exit-error)
;; procedure void -> void
(final-page installer-final-page)
@@ -91,4 +94,10 @@
;; procedure (menu-proc) -> void
(parameters-menu installer-parameters-menu)
;; procedure (keyboard-layout-selection) -> void
(parameters-page installer-parameters-page))
(parameters-page installer-parameters-page)
;; procedure (dump) -> void
(dump-page installer-dump-page)
;; procedure command -> bool
(run-command installer-run-command)
;; procedure (report) -> void
(report-page installer-report-page))

View File

@@ -28,13 +28,7 @@
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#:use-module (rnrs io ports)
#:export (&installer-step-abort
installer-step-abort?
&installer-step-break
installer-step-break?
<installer-step>
#:export (<installer-step>
installer-step
make-installer-step
installer-step?
@@ -52,15 +46,13 @@
%installer-configuration-file
%installer-target-dir
format-configuration
configuration->file))
configuration->file
;; This condition may be raised to abort the current step.
(define-condition-type &installer-step-abort &condition
installer-step-abort?)
%current-result))
;; This condition may be raised to break out from the steps execution.
(define-condition-type &installer-step-break &condition
installer-step-break?)
;; Hash table storing the step results. Use it only for logging and debug
;; purposes.
(define %current-result (make-hash-table))
;; An installer-step record is basically an id associated to a compute
;; procedure. The COMPUTE procedure takes exactly one argument, an association
@@ -88,8 +80,10 @@
(rewind-strategy 'previous)
(menu-proc (const #f)))
"Run the COMPUTE procedure of all <installer-step> records in STEPS
sequentially. If the &installer-step-abort condition is raised, fallback to a
previous install-step, accordingly to the specified REWIND-STRATEGY.
sequentially, inside a the 'installer-step prompt. When aborted to with a
parameter of 'abort, fallback to a previous install-step, accordingly to the
specified REWIND-STRATEGY. When aborted to with a parameter of 'break, stop
the computation and return the accumalated result so far.
REWIND-STRATEGY possible values are 'previous, 'menu and 'start. If 'previous
is selected, the execution will resume at the previous installer-step. If
@@ -106,10 +100,7 @@ the form:
where STEP-ID is the ID field of the installer-step and COMPUTE-RESULT the
result of the associated COMPUTE procedure. This result association list is
passed as argument of every COMPUTE procedure. It is finally returned when the
computation is over.
If the &installer-step-break condition is raised, stop the computation and
return the accumalated result so far."
computation is over."
(define (pop-result list)
(cdr list))
@@ -143,62 +134,61 @@ return the accumalated result so far."
(match todo-steps
(() (reverse result))
((step . rest-steps)
(guard (c ((installer-step-abort? c)
(case rewind-strategy
((previous)
(match done-steps
(()
;; We cannot go previous the first step. So re-raise
;; the exception. It might be useful in the case of
;; nested run-installer-steps. Abort to 'raise-above
;; prompt to prevent the condition from being catched
;; by one of the previously installed guard.
(abort-to-prompt 'raise-above c))
((prev-done ... last-done)
(run (pop-result result)
#:todo-steps (cons last-done todo-steps)
#:done-steps prev-done))))
((menu)
(let ((goto-step (menu-proc
(append done-steps (list step)))))
(if (eq? goto-step step)
(run result
#:todo-steps todo-steps
#:done-steps done-steps)
(skip-to-step goto-step result
#:todo-steps todo-steps
#:done-steps done-steps))))
((start)
(if (null? done-steps)
;; Same as above, it makes no sense to jump to start
;; when we are at the first installer-step. Abort to
;; 'raise-above prompt to re-raise the condition.
(abort-to-prompt 'raise-above c)
(run '()
#:todo-steps steps
#:done-steps '())))))
((installer-step-break? c)
(reverse result)))
(syslog "running step '~a'~%" (installer-step-id step))
(let* ((id (installer-step-id step))
(compute (installer-step-compute step))
(res (compute result done-steps)))
(run (alist-cons id res result)
#:todo-steps rest-steps
#:done-steps (append done-steps (list step))))))))
(call-with-prompt 'installer-step
(lambda ()
(installer-log-line "running step '~a'" (installer-step-id step))
(let* ((id (installer-step-id step))
(compute (installer-step-compute step))
(res (compute result done-steps)))
(hash-set! %current-result id res)
(run (alist-cons id res result)
#:todo-steps rest-steps
#:done-steps (append done-steps (list step)))))
(lambda (k action)
(match action
('abort
(case rewind-strategy
((previous)
(match done-steps
(()
;; We cannot go previous the first step. Abort again to
;; 'installer-step prompt. It might be useful in the case
;; of nested run-installer-steps.
(abort-to-prompt 'installer-step action))
((prev-done ... last-done)
(run (pop-result result)
#:todo-steps (cons last-done todo-steps)
#:done-steps prev-done))))
((menu)
(let ((goto-step (menu-proc
(append done-steps (list step)))))
(if (eq? goto-step step)
(run result
#:todo-steps todo-steps
#:done-steps done-steps)
(skip-to-step goto-step result
#:todo-steps todo-steps
#:done-steps done-steps))))
((start)
(if (null? done-steps)
;; Same as above, it makes no sense to jump to start
;; when we are at the first installer-step. Abort to
;; 'installer-step prompt again.
(abort-to-prompt 'installer-step action)
(run '()
#:todo-steps steps
#:done-steps '())))))
('break
(reverse result))))))))
;; Ignore SIGPIPE so that we don't die if a client closes the connection
;; prematurely.
(sigaction SIGPIPE SIG_IGN)
(with-server-socket
(call-with-prompt 'raise-above
(lambda ()
(run '()
#:todo-steps steps
#:done-steps '()))
(lambda (k condition)
(raise condition)))))
(run '()
#:todo-steps steps
#:done-steps '())))
(define (find-step-by-id steps id)
"Find and return the step in STEPS whose id is equal to ID."

View File

@@ -19,7 +19,14 @@
(define-module (gnu installer user)
#:use-module (guix records)
#:use-module (srfi srfi-1)
#:export (<user>
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-9 gnu)
#:export (<secret>
secret?
make-secret
secret-content
<user>
user
make-user
user-name
@@ -30,6 +37,16 @@
users->configuration))
(define-record-type <secret>
(make-secret content)
secret?
(content secret-content))
(set-record-type-printer!
<secret>
(lambda (secret port)
(format port "<secret>")))
(define-record-type* <user>
user make-user
user?

View File

@@ -25,7 +25,10 @@
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-19)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#: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)
@@ -34,10 +37,17 @@
read-all
nearest-exact-integer
read-percentage
run-external-command-with-handler
run-external-command-with-line-hooks
run-command
run-command-in-installer
syslog-port
syslog
%syslog-line-hook
installer-log-port
%installer-log-line-hook
%default-installer-line-hooks
installer-log-line
call-with-time
let/time
@@ -74,37 +84,99 @@ number. If no percentage is found, return #f"
(and result
(string->number (match:substring result 1)))))
(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)))
;; Hack to work around Guile bug 52835
(define dup-output (duplicate-port output "w"))
;; Void pipe, but holds the pid for close-pipe.
(define dummy-pipe
(with-input-from-file "/dev/null"
(lambda ()
(with-output-to-port output
(lambda ()
(with-error-to-port dup-output
(lambda ()
(apply open-pipe* (cons "" command)))))))))
(close-port output)
(close-port dup-output)
(handler input)
(close-port input)
(close-pipe dummy-pipe)))
(define (run-external-command-with-line-hooks line-hooks command)
"Run command specified by the list COMMAND 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")
(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?)
(guard (c ((invoke-error? c)
(newline)
(format (current-error-port)
(G_ "Command failed with exit code ~a.~%")
(invoke-error-exit-status c))
(syslog "command ~s failed with exit code ~a"
command (invoke-error-exit-status c))
(pause)
#f))
(syslog "running command ~s~%" command)
(apply invoke command)
(syslog "command ~s succeeded~%" command)
(newline)
(pause)
#t))
(define run-command-in-installer
(make-parameter
(lambda (. args)
(raise
(condition
(&serious)
(&message (message "run-command-in-installer not set")))))))
;;;
@@ -142,6 +214,9 @@ values."
(set! port (open-syslog-port)))
(or port (%make-void-port "w")))))
(define (%syslog-line-hook line)
(format (syslog-port) "installer[~d]: ~a~%" (getpid) line))
(define-syntax syslog
(lambda (s)
"Like 'format', but write to syslog."
@@ -152,6 +227,43 @@ values."
(syntax->datum #'fmt))))
#'(format (syslog-port) fmt (getpid) args ...))))))
(define (open-new-log-port)
(define now (localtime (time-second (current-time))))
(define filename
(format #f "/tmp/installer.~a.log"
(strftime "%F.%T" now)))
(open filename (logior O_RDWR
O_CREAT)))
(define installer-log-port
(let ((port #f))
(lambda ()
"Return an input and output port to the installer log."
(unless port
(set! port (open-new-log-port)))
port)))
(define (%installer-log-line-hook line)
(format (installer-log-port) "~a~%" line))
(define (%display-line-hook line)
(display line)
(newline))
(define %default-installer-line-hooks
(list %syslog-line-hook
%installer-log-line-hook))
(define-syntax installer-log-line
(lambda (s)
"Like 'format', but uses the default line hooks, and only formats one line."
(syntax-case s ()
((_ fmt args ...)
(string? (syntax->datum #'fmt))
#'(let ((formatted (format #f fmt args ...)))
(for-each (lambda (f) (f formatted))
%default-installer-line-hooks))))))
;;;
;;; Client protocol.
@@ -214,8 +326,9 @@ accepting socket."
(let ((errno (system-error-errno args)))
(if (memv errno (list EPIPE ECONNRESET ECONNABORTED))
(begin
(syslog "removing client ~s due to ~s while replying~%"
(fileno client) (strerror errno))
(installer-log-line
"removing client ~s due to ~s while replying"
(fileno client) (strerror errno))
(false-if-exception (close-port client))
remainder)
(cons client remainder))))))

View File

@@ -756,6 +756,7 @@ GNU_SYSTEM_MODULES = \
INSTALLER_MODULES = \
%D%/installer.scm \
%D%/installer/connman.scm \
%D%/installer/dump.scm \
%D%/installer/final.scm \
%D%/installer/hostname.scm \
%D%/installer/keymap.scm \