aboutsummaryrefslogtreecommitdiff
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2018, 2021 Mathieu Othacehe <othacehe@gnu.org>
;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de>
;;;
;;; 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 keymap)
  #:use-module (guix records)
  #:use-module (sxml match)
  #:use-module (sxml simple)
  #:use-module (ice-9 binary-ports)
  #:use-module (ice-9 ftw)
  #:use-module (ice-9 match)
  #:use-module (ice-9 regex)
  #:export (<x11-keymap-model>
            x11-keymap-model
            make-x11-keymap-model
            x11-keymap-model?
            x11-keymap-model-name
            x11-keymap-model-description

            <x11-keymap-layout>
            x11-keymap-layout
            make-x11-keymap-layout
            x11-keymap-layout?
            x11-keymap-layout-name
            x11-keymap-layout-synopsis
            x11-keymap-layout-description
            x11-keymap-layout-variants

            <x11-keymap-variant>
            x11-keymap-variant
            make-x11-keymap-variant
            x11-keymap-variant?
            x11-keymap-variant-name
            x11-keymap-variant-description

            default-keyboard-model
            xkb-rules->models+layouts
            kmscon-update-keymap))

(define-record-type* <x11-keymap-model>
  x11-keymap-model make-x11-keymap-model
  x11-keymap-model?
  (name            x11-keymap-model-name) ;string
  (description     x11-keymap-model-description)) ;string

(define-record-type* <x11-keymap-layout>
  x11-keymap-layout make-x11-keymap-layout
  x11-keymap-layout?
  (name            x11-keymap-layout-name) ;string
  (synopsis        x11-keymap-layout-synopsis)    ;string (e.g., "en")
  (description     x11-keymap-layout-description) ;string (a whole phrase)
  (variants        x11-keymap-layout-variants)) ;list of <x11-keymap-variant>

(define-record-type* <x11-keymap-variant>
  x11-keymap-variant make-x11-keymap-variant
  x11-keymap-variant?
  (name            x11-keymap-variant-name) ;string
  (description     x11-keymap-variant-description)) ;string

;; Assume all modern keyboards have this model.
(define default-keyboard-model (make-parameter "pc105"))

(define (xkb-rules->models+layouts file)
  "Parse FILE and return two values, the list of supported X11-KEYMAP-MODEL
and X11-KEYMAP-LAYOUT records. FILE is an XML file from the X Keyboard
Configuration Database, describing possible XKB configurations."
  (define maybe-empty
    (match-lambda
      ((x) x)
      (#f "")))

  (define (model m)
    (sxml-match m
                [(model
                  (configItem
                   (name ,name)
                   (description ,description)
                   . ,rest))
                 (x11-keymap-model
                  (name name)
                  (description description))]))

  (define (variant v)
    (sxml-match v
                [(variant
                  ;; According to xbd-rules DTD, the definition of a
                  ;; configItem is: <!ELEMENT configItem
                  ;; (name,shortDescription*,description*,vendor?,
                  ;; countryList?,languageList?,hwList?)>
                  ;;
                  ;; shortDescription and description are optional elements
                  ;; but sxml-match does not support default values for
                  ;; elements (only attributes). So to avoid writing as many
                  ;; patterns as existing possibilities, gather all the
                  ;; remaining elements but name in REST-VARIANT.
                  (configItem
                   (name ,name)
                   . ,rest-variant))
                 (x11-keymap-variant
                  (name name)
                  (description (maybe-empty
                                (assoc-ref rest-variant 'description))))]))

  (define (layout l)
    (sxml-match l
                [(layout
                  (configItem
                   (name ,name)
                   . ,rest-layout)
                  (variantList ,[variant -> v] ...))
                 (x11-keymap-layout
                  (name name)
                  (synopsis (maybe-empty
                             (assoc-ref rest-layout 'shortDescription)))
                  (description (maybe-empty
                                (assoc-ref rest-layout 'description)))
                  (variants (list v ...)))]
                [(layout
                  (configItem
                   (name ,name)
                   . ,rest-layout))
                 (x11-keymap-layout
                  (name name)
                  (synopsis (maybe-empty
                             (assoc-ref rest-layout 'shortDescription)))
                  (description (maybe-empty
                                (assoc-ref rest-layout 'description)))
                  (variants '()))]))

  (let ((sxml (call-with-input-file file
                (lambda (port)
                  (xml->sxml port #:trim-whitespace? #t)))))
    (match
        (sxml-match sxml
                    [(*TOP*
                      ,pi
                      (xkbConfigRegistry
                       (@ . ,ignored)
                       (modelList ,[model -> m] ...)
                       (layoutList ,[layout -> l] ...)
                       . ,rest))
                     (list
                      (list m ...)
                      (list l ...))])
      ((models layouts)
       (values models layouts)))))

(define (kmscon-update-keymap model layout variant options)
  "Update kmscon keymap with the provided MODEL, LAYOUT, VARIANT and OPTIONS."
  (and=>
   (getenv "KEYMAP_UPDATE")
   (lambda (keymap-file)
     (unless (file-exists? keymap-file)
       (error "Unable to locate keymap update file"))

     ;; See file gnu/packages/patches/kmscon-runtime-keymap-switch.patch.
     ;; This dirty hack makes possible to update kmscon keymap at runtime by
     ;; writing an X11 keyboard model, layout and variant to a named pipe
     ;; referred by KEYMAP_UPDATE environment variable.
     (call-with-output-file keymap-file
       (lambda (port)
         (format port model)
         (put-u8 port 0)

         (format port layout)
         (put-u8 port 0)

         (format port (or variant ""))
         (put-u8 port 0)

         (format port (or options ""))
         (put-u8 port 0))))))
l)[expectedHashStr]: Remove. (SubstitutionGoal::finished): Tokenize 'status'. Parse it and handle "success" and "hash-mismatch" accordingly. Call 'hashPath' only when the returned hash is not SHA256. (SubstitutionGoal::handleChildOutput): Remove 'expectedHashStr' handling. * tests/substitute.scm ("substitute, invalid hash"): Rename to... ("substitute, invalid narinfo hash"): ... this. ("substitute, invalid hash"): New test. Ludovic Courtès 2020-12-08daemon: Raise an error if substituter doesn't send the expected hash....It was already impossible in practice for 'expectedHashStr' to be empty if 'status' == "success". * nix/libstore/build.cc (SubstitutionGoal::finished): Throw 'SubstError' when 'expectedHashStr' is empty. Ludovic Courtès 2020-12-08substitute: Cache and reuse connections while substituting....That way, when fetching a series of substitutes from the same server(s), the connection is reused instead of being closed/opened for each substitutes, which saves on network round trips and TLS handshakes. * guix/http-client.scm (http-fetch): Add #:keep-alive? and honor it. * guix/progress.scm (progress-report-port): Add #:close? parameter and honor it. * guix/scripts/substitute.scm (at-most): Return the tail as a second value. (fetch): Add #:port and #:keep-alive? and honor them. (%max-cached-connections): New variable. (open-connection-for-uri/cached, call-with-cached-connection): New procedures. (with-cached-connection): New macro. (process-substitution): Wrap 'fetch' call in 'with-cached-connection'. Pass #:close? to 'progress-report-port'. Ludovic Courtès 2020-12-08daemon: Run 'guix substitute --substitute' as an agent....This avoids spawning one substitute process per substitution. * nix/libstore/build.cc (class Worker)[substituter]: New field. [outPipe, logPipe, pid]: Remove. (class SubstitutionGoal)[expectedHashStr, status, substituter]: New fields. (SubstitutionGoal::timedOut): Adjust to check 'substituter'. (SubstitutionGoal::tryToRun): Remove references to 'outPipe' and 'logPipe'. Run "guix substitute --substitute" as an 'Agent'. Send the request with 'writeLine'. (SubstitutionGoal::finished): Likewise. (SubstitutionGoal::handleChildOutput): Change to fill in 'expectedHashStr' and 'status'. (SubstitutionGoal::handleEOF): Call 'wakeUp' unconditionally. (SubstitutionGoal::~SubstitutionGoal): Adjust to check 'substituter'. * guix/scripts/substitute.scm (process-substitution): Write "success\n" to stdout upon success. (%error-to-file-descriptor-4?): New variable. (guix-substitute): Set 'current-error-port' to file descriptor 4 unless (%error-to-file-descriptor-4?) is false. Remove "--substitute" arguments. Loop reading line from stdin. * tests/substitute.scm <top level>: Call '%error-to-file-descriptor-4?'. (request-substitution): New procedure. ("substitute, no signature") ("substitute, invalid hash") ("substitute, unauthorized key") ("substitute, authorized key") ("substitute, unauthorized narinfo comes first") ("substitute, unsigned narinfo comes first") ("substitute, first narinfo is unsigned and has wrong hash") ("substitute, first narinfo is unsigned and has wrong refs") ("substitute, two invalid narinfos") ("substitute, narinfo with several URLs"): Adjust to new "guix substitute --substitute" calling convention. Ludovic Courtès 2020-12-08daemon: Use 'Agent' to spawn 'guix substitute --query'....* nix/libstore/local-store.hh (RunningSubstituter): Remove. (LocalStore)[runningSubstituter]: Change to unique_ptr<Agent>. [setSubstituterEnv, didSetSubstituterEnv]: Remove. [getLineFromSubstituter, getIntLineFromSubstituter]: Take an 'Agent'. * nix/libstore/local-store.cc (LocalStore::~LocalStore): Remove reference to 'runningSubstituter'. (LocalStore::setSubstituterEnv, LocalStore::startSubstituter): Remove. (LocalStore::getLineFromSubstituter): Adjust to 'run' being an 'Agent'. (LocalStore::querySubstitutablePaths): Spawn substituter agent if needed. Adjust to 'Agent' interface. (LocalStore::querySubstitutablePathInfos): Likewise. * nix/libstore/build.cc (SubstitutionGoal::tryToRun): Remove call to 'setSubstituterEnv' and add 'setenv' call for "_NIX_OPTIONS" instead. (SubstitutionGoal::finished): Remove 'readLine' call for 'dummy'. * guix/scripts/substitute.scm (%allow-unauthenticated-substitutes?): Remove second argument to 'make-parameter'. (process-query): Call 'warn-about-missing-authentication' when (%allow-unauthenticated-substitutes?) is #t. (guix-substitute): Wrap body in 'parameterize'. Set 'guix-warning-port' too. No longer exit when 'substitute-urls' returns the empty list. No longer print newline initially. * tests/substitute.scm (test-quit): Parameterize 'current-error-port' to account for the port changes in 'guix-substitute'. Ludovic Courtès 2020-12-01daemon: Remove unneeded forward declaration....This is a followup to ee9dff34f9317509cb2b833d07a0d5e01a36a4ae. * nix/libstore/build.cc: Remove 'struct Agent' forward declaration. Ludovic Courtès 2020-11-29daemon: Remove pre-Guix hack....* nix/libstore/build.cc (DerivationGoal::startBuilder): Remove "NIX_OUTPUT_CHECKED" hack. Ludovic Courtès 2020-10-09nix: Honor '--rounds' when also using '--check'....Fixes <https://issues.guix.gnu.org/40144>. Until now, the '--rounds' option, when also using '--check', was ignored. This change makes it possible to use both, so that an item that has already been built once can be rebuilt as many times as desired. * nix/libstore/build.cc: Remove the conditionals causing the daemon to complete a build task early when 'buildMode' is equal to 'nix::bmCheck'. Reported-by: Brice Waegeneire <brice@waegenei.re> Maxim Cournoyer 2020-10-01daemon: Try to execute derivation builders only for matching OS kernels....Fixes <https://bugs.gnu.org/43668>. Previously, guix-daemon would try to run GNU/Hurd executables on GNU/Linux. execve(2) would succeed, but the executable would immediately crash. This change prevents it from attempting to execute "i586-gnu" code on "*-linux", while preserving the binfmt_misc-friendly behavior implemented in commit 7bf2a70a4ffd976d50638d3b9f2ec409763157df. * nix/libstore/build.cc (sameOperatingSystemKernel): New function. (DerivationGoal::runChild): Call 'execve' only when 'sameOperatingSystemKernel' returns true. Ludovic Courtès 2020-09-14daemon: Move 'Agent' to libutil....* nix/libstore/build.cc (DerivationGoal::tryBuildHook): Add "offload" to 'args' and pass settings.guixProgram as the first argument to Agent::Agent. (pathNullDevice, commonChildInit, Agent, Agent::Agent) (Agent::~Agent): Move to... * nix/libutil/util.cc: ... here. * nix/libutil/util.hh (struct Agent, commonChildInit): New declarations. Ludovic Courtès 2020-09-14daemon: Generalize 'HookInstance' to 'Agent'....* nix/libstore/build.cc (HookInstance): Rename to... (Agent): ... this. Rename 'toHook' and 'fromHook' similarly and update users. Change constructor to require a command and an argument list. (DerivationGoal::tryBuildHook): Pass arguments to the 'Agent' constructor. Ludovic Courtès