summary refs log tree commit diff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/contributing.texi37
-rw-r--r--doc/guix-cookbook.texi53
-rw-r--r--doc/guix.texi1080
3 files changed, 1095 insertions, 75 deletions
diff --git a/doc/contributing.texi b/doc/contributing.texi
index 2a73d2c47a..f5d73e78aa 100644
--- a/doc/contributing.texi
+++ b/doc/contributing.texi
@@ -42,30 +42,27 @@ git clone https://git.savannah.gnu.org/git/guix.git
 
 @cindex authentication, of a Guix checkout
 How do you ensure that you obtained a genuine copy of the repository?
-Guix itself provides a tool to @dfn{authenticate} your checkout, but you
-must first make sure this tool is genuine in order to ``bootstrap'' the
-trust chain.  To do that, run:
+To do that, run @command{guix git authenticate}, passing if the commit
+and OpenPGP fingerprint of the @dfn{channel introduction}
+(@pxref{Invoking guix git authenticate}):
 
-@c XXX: Adjust instructions when there's a known tag to start from.
+@c The commit and fingerprint below must match those of the channel
+@c introduction in '%default-channels'.
 @example
-git verify-commit `git log --format=%H build-aux/git-authenticate.scm`
-@end example
-
-The output must look something like:
-
-@example
-gpg: Signature made Fri 27 Dec 2019 01:27:41 PM CET
-gpg:                using RSA key 3CE464558A84FDC69DB40CFB090B11993D9AEBB5
-@dots{}
-gpg: Signature made Fri 27 Dec 2019 01:25:22 PM CET
-gpg:                using RSA key 3CE464558A84FDC69DB40CFB090B11993D9AEBB5
-@dots{}
+guix git authenticate 9edb3f66fd807b096b48283debdcddccfea34bad \
+  "BBB0 2DDF 2CEA F6A8 0D1D  E643 A2A0 6DF2 A33A 54FA"
 @end example
 
 @noindent
-... meaning that changes to this file are all signed with key
-@code{3CE464558A84FDC69DB40CFB090B11993D9AEBB5} (you may need to fetch
-this key from a key server, if you have not done it yet).
+This command completes with exit code zero on success; it prints an
+error message and exits with a non-zero code otherwise.
+
+As you can see, there is a chicken-and-egg problem: you first need to
+have Guix installed.  Typically you would install Guix System
+(@pxref{System Installation}) or Guix on top of another distro
+(@pxref{Binary Installation}); in either case, you would verify the
+OpenPGP signature on the installation medium.  This ``bootstraps'' the
+trust chain.
 
 The easiest way to set up a development environment for Guix is, of
 course, by using Guix!  The following command starts a new shell where
@@ -277,7 +274,7 @@ trigger string @code{origin...}, which can be expanded further.  The
 @cindex insert or update copyright
 @cindex @code{M-x guix-copyright}
 @cindex @code{M-x copyright-update}
-Additionaly we provide insertion and automatic update of a copyright in
+We additionally provide insertion and automatic update of a copyright in
 @file{etc/copyright.el}.  You may want to set your full name, mail, and
 load a file.
 
diff --git a/doc/guix-cookbook.texi b/doc/guix-cookbook.texi
index 1342826c97..f541592d13 100644
--- a/doc/guix-cookbook.texi
+++ b/doc/guix-cookbook.texi
@@ -15,6 +15,7 @@ Copyright @copyright{} 2020 Oleg Pykhalov@*
 Copyright @copyright{} 2020 Matthew Brooks@*
 Copyright @copyright{} 2020 Marcin Karpezo@*
 Copyright @copyright{} 2020 Brice Waegeneire@*
+Copyright @copyright{} 2020 André Batista@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -109,8 +110,8 @@ Let's get started!
 
 Guix uses the Guile implementation of Scheme.  To start playing with the
 language, install it with @code{guix install guile} and start a
-@uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop,
-REPL} by running @code{guile} from the command line.
+@dfn{REPL}---short for @uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop,
+@dfn{read-eval-print loop}}---by running @code{guile} from the command line.
 
 Alternatively you can also run @code{guix environment --ad-hoc guile -- guile}
 if you'd rather not have Guile installed in your user profile.
@@ -118,7 +119,7 @@ if you'd rather not have Guile installed in your user profile.
 In the following examples, lines show what you would type at the REPL;
 lines starting with ``@result{}'' show evaluation results, while lines
 starting with ``@print{}'' show things that get printed.  @xref{Using Guile
-Interactively,,, guile, GNU Guile Reference Manual}), for more details on the
+Interactively,,, guile, GNU Guile Reference Manual}, for more details on the
 REPL.
 
 @itemize
@@ -843,12 +844,32 @@ tags, so if the @code{version} is tagged, then it can be used directly.  Sometim
 the tag is prefixed with a @code{v}, in which case you'd use @code{(commit (string-append
 "v" version))}.
 
-To ensure that the source code from the Git repository is stored in a unique
-directory with a readable name we use @code{(file-name (git-file-name name
+To ensure that the source code from the Git repository is stored in a
+directory with a descriptive name, we use @code{(file-name (git-file-name name
 version))}.
 
-Note that there is also a @code{git-version} procedure that can be used to derive the
-version when packaging programs for a specific commit.
+The @code{git-version} procedure can be used to derive the
+version when packaging programs for a specific commit, following the
+Guix contributor guidelines (@pxref{Version Numbers,,, guix, GNU Guix
+Reference Manual}).
+
+How does one obtain the @code{sha256} hash that's in there, you ask?  By
+invoking @command{guix hash} on a checkout of the desired commit, along
+these lines:
+
+@example
+git clone https://github.com/libgit2/libgit2/
+cd libgit2
+git checkout v0.26.6
+guix hash -rx .
+@end example
+
+@command{guix hash -rx} computes a SHA256 hash over the whole directory,
+excluding the @file{.git} sub-directory (@pxref{Invoking guix hash,,,
+guix, GNU Guix Reference Manual}).
+
+In the future, @command{guix download} will hopefully be able to do
+these steps for you, just like it does for regular downloads.
 
 @subsubsection Snippets
 
@@ -1267,7 +1288,7 @@ version or compilation options.
 @subsection Getting help
 
 Sadly, some applications can be tough to package.  Sometimes they need a patch to
-work with the non-standard filesystem hierarchy enforced by the store.
+work with the non-standard file system hierarchy enforced by the store.
 Sometimes the tests won't run properly.  (They can be skipped but this is not
 recommended.)  Other times the resulting package won't be reproducible.
 
@@ -1480,7 +1501,7 @@ custom kernel:
 @lisp
 (define %macbook41-full-config
   (append %macbook41-config-options
-          %filesystems
+          %file-systems
           %efi-support
           %emulation
           (@@@@ (gnu packages linux) %default-extra-linux-options)))
@@ -1496,8 +1517,8 @@ custom kernel:
                       #:extra-options %macbook41-config-options))
 @end lisp
 
-In the above example @code{%filesystems} is a collection of flags enabling
-different filesystem support, @code{%efi-support} enables EFI support and
+In the above example @code{%file-systems} is a collection of flags enabling
+different file system support, @code{%efi-support} enables EFI support and
 @code{%emulation} enables a x86_64-linux machine to act in 32-bit mode also.
 @code{%default-extra-linux-options} are the ones quoted above, which had to be
 added in since they were replaced in the @code{extra-options} keyword.
@@ -1561,7 +1582,7 @@ The second way to setup the kernel configuration makes more use of Guix's
 features and allows you to share configuration segments between different
 kernels.  For example, all machines using EFI to boot have a number of EFI
 configuration flags that they need.  It is likely that all the kernels will
-share a list of filesystems to support.  By using variables it is easier to
+share a list of file systems to support.  By using variables it is easier to
 see at a glance what features are enabled and to make sure you don't have
 features in one kernel but missing in another.
 
@@ -1799,10 +1820,16 @@ HTTP/HTTPS will get proxied; FTP, Git protocol, SSH, etc connections
 will still go through the clearnet.  Again, this configuration isn't
 foolproof some of your traffic won't get routed by Tor at all.  Use it
 at your own risk.
+
+Also note that the procedure described here applies only to package
+substitution. When you update your guix distribution with
+@command{guix pull}, you still need to use @command{torsocks} if
+you want to route the connection to guix's git repository servers
+through Tor.
 @end quotation
 
 Guix's substitute server is available as a Onion service, if you want
-to use it to get your substitutes from Tor configure your system as
+to use it to get your substitutes through Tor configure your system as
 follow:
 
 @lisp
diff --git a/doc/guix.texi b/doc/guix.texi
index 59085b6afd..7beb2c3f27 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -52,7 +52,7 @@ Copyright @copyright{} 2017, 2019, 2020 Maxim Cournoyer@*
 Copyright @copyright{} 2017, 2018, 2019, 2020 Tobias Geerinckx-Rice@*
 Copyright @copyright{} 2017 George Clemmer@*
 Copyright @copyright{} 2017 Andy Wingo@*
-Copyright @copyright{} 2017, 2018, 2019 Arun Isaac@*
+Copyright @copyright{} 2017, 2018, 2019, 2020 Arun Isaac@*
 Copyright @copyright{} 2017 nee@*
 Copyright @copyright{} 2018 Rutger Helling@*
 Copyright @copyright{} 2018 Oleg Pykhalov@*
@@ -791,11 +791,11 @@ The following dependencies are optional:
 
 @itemize
 @item
-@c Note: We need at least 0.12.0 for 'userauth-gssapi!'.
+@c Note: We need at least 0.13.0 for #:nodelay.
 Support for build offloading (@pxref{Daemon Offload Setup}) and
 @command{guix copy} (@pxref{Invoking guix copy}) depends on
 @uref{https://github.com/artyom-poptsov/guile-ssh, Guile-SSH},
-version 0.12.0 or later.
+version 0.13.0 or later.
 
 @item
 When @url{https://www.nongnu.org/lzip/lzlib.html, lzlib} is available, lzlib
@@ -1978,7 +1978,7 @@ its device name.  Assuming that the USB stick is known as @file{/dev/sdX},
 copy the image with:
 
 @example
-dd if=guix-system-install-@value{VERSION}.x86_64-linux.iso of=/dev/sdX
+dd if=guix-system-install-@value{VERSION}.x86_64-linux.iso of=/dev/sdX status=progress
 sync
 @end example
 
@@ -3975,8 +3975,48 @@ deploys Guix itself from the official GNU@tie{}Guix repository.  This can be
 customized by defining @dfn{channels} in the
 @file{~/.config/guix/channels.scm} file.  A channel specifies a URL and branch
 of a Git repository to be deployed, and @command{guix pull} can be instructed
-to pull from one or more channels.  In other words, channels can be used to
-@emph{customize} and to @emph{extend} Guix, as we will see below.
+to pull from one or more channels.  In other words, channels can be used
+to @emph{customize} and to @emph{extend} Guix, as we will see below.
+Before that, some security considerations.
+
+@subsection Channel Authentication
+
+@anchor{channel-authentication}
+@cindex authentication, of channel code
+The @command{guix pull} and @command{guix time-machine} commands
+@dfn{authenticate} the code retrieved from channels: they make sure each
+commit that is fetched is signed by an authorized developer.  The goal
+is to protect from unauthorized modifications to the channel that would
+lead users to run malicious code.
+
+As a user, you must provide a @dfn{channel introduction} in your
+channels file so that Guix knows how to authenticate its first commit.
+A channel specification, including its introduction, looks something
+along these lines:
+
+@lisp
+(channel
+  (name 'my-channel)
+  (url "https://example.org/my-channel.git")
+  (introduction
+   (make-channel-introduction
+    "6f0d8cc0d88abb59c324b2990bfee2876016bb86"
+    (openpgp-fingerprint
+     "CABB A931 C0FF EEC6 900D  0CFB 090B 1199 3D9A EBB5"))))
+@end lisp
+
+The specification above shows the name and URL of the channel.  The call
+to @code{make-channel-introduction} above specifies that authentication
+of this channel starts at commit @code{6f0d8cc@dots{}}, which is signed
+by the OpenPGP key with fingerprint @code{CABB A931@dots{}}.
+
+For the main channel, called @code{guix}, you automatically get that
+information from your Guix installation.  For other channels, include
+the channel introduction provided by the channel authors in your
+@file{channels.scm} file.  Make sure you retrieve the channel
+introduction from a trusted source since that is the root of your trust.
+
+If you're curious about the authentication mechanics, read on!
 
 @subsection Using a Custom Guix Channel
 
@@ -4121,7 +4161,15 @@ The meta-data file should contain a simple S-expression like this:
  (dependencies
   (channel
    (name some-collection)
-   (url "https://example.org/first-collection.git"))
+   (url "https://example.org/first-collection.git")
+
+   ;; The 'introduction' bit below is optional: you would
+   ;; provide it for dependencies that can be authenticated.
+   (introduction
+    (channel-introduction
+      (version 0)
+      (commit "a8883b58dc82e167c96506cf05095f37c2c2c6cd")
+      (signer "CABB A931 C0FF EEC6 900D  0CFB 090B 1199 3D9A EBB5"))))
   (channel
    (name some-other-collection)
    (url "https://example.org/second-collection.git")
@@ -4150,6 +4198,88 @@ add a meta-data file @file{.guix-channel} that contains:
   (directory "guix"))
 @end lisp
 
+@cindex channel authorizations
+@subsection Specifying Channel Authorizations
+
+@anchor{channel-authorizations}
+As we saw above, Guix ensures the source code it pulls from channels
+comes from authorized developers.  As a channel author, you need to
+specify the list of authorized developers in the
+@file{.guix-authorizations} file in the channel's Git repository.  The
+authentication rule is simple: each commit must be signed by a key
+listed in the @file{.guix-authorizations} file of its parent
+commit(s)@footnote{Git commits form a @dfn{directed acyclic graph}
+(DAG).  Each commit can have zero or more parents; ``regular'' commits
+have one parent and merge commits have two parent commits.  Read
+@uref{https://eagain.net/articles/git-for-computer-scientists/, @i{Git
+for Computer Scientists}} for a great overview.}  The
+@file{.guix-authorizations} file looks like this:
+
+@lisp
+;; Example '.guix-authorizations' file.
+
+(authorizations
+ (version 0)               ;current file format version
+
+ (("AD17 A21E F8AE D8F1 CC02  DBD9 F8AE D8F1 765C 61E3"
+   (name "alice"))
+  ("2A39 3FFF 68F4 EF7A 3D29  12AF 68F4 EF7A 22FB B2D5"
+   (name "bob"))
+  ("CABB A931 C0FF EEC6 900D  0CFB 090B 1199 3D9A EBB5"
+   (name "charlie"))))
+@end lisp
+
+Each fingerprint is followed by optional key/value pairs, as in the
+example above.  Currently these key/value pairs are ignored.
+
+This authentication rule creates a chicken-and-egg issue: how do we
+authenticate the first commit?  Related to that: how do we deal with
+channels whose repository history contains unsigned commits and lack
+@file{.guix-authorizations}?  And how do we fork existing channels?
+
+@cindex channel introduction
+Channel introductions answer these questions by describing the first
+commit of a channel that should be authenticated.  The first time a
+channel is fetched with @command{guix pull} or @command{guix
+time-machine}, the command looks up the introductory commit and verifies
+that it is signed by the specified OpenPGP key.  From then on, it
+authenticates commits according to the rule above.
+
+To summarize, as the author of a channel, there are two things you have
+to do to allow users to authenticate your code:
+
+@enumerate
+@item
+Introduce an initial @file{.guix-authorizations} in the channel's
+repository.  Do that in a signed commit (@pxref{Commit Access}, for
+information on how to sign Git commits.)
+
+@item
+Advertise the channel introduction, for instance on your channel's web
+page.  The channel introduction, as we saw above, is the commit/key
+pair---i.e., the commit that introduced @file{.guix-authorizations}, and
+the fingerprint of the OpenPGP used to sign it.
+@end enumerate
+
+Before pushing to your public Git repository, you can run @command{guix
+git-authenticate} to verify that you did sign all the commits you are
+about to push with an authorized key:
+
+@example
+guix git authenticate @var{commit} @var{signer}
+@end example
+
+@noindent
+where @var{commit} and @var{signer} are your channel introduction.
+@xref{Invoking guix git authenticate}, for details.
+
+Publishing a signed channel requires discipline: any mistake, such as an
+unsigned commit or a commit signed by an unauthorized key, will prevent
+users from pulling from your channel---well, that's the whole point of
+authentication!  Pay attention to merges in particular: merge commits
+are considered authentic if and only if they are signed by a key present
+in the @file{.guix-authorizations} file of @emph{both} branches.
+
 @cindex primary URL, channels
 @subsection Primary URL
 
@@ -4500,7 +4630,12 @@ $ guix describe -f channels
         (name 'guix)
         (url "https://git.savannah.gnu.org/git/guix.git")
         (commit
-          "e0fa68c7718fffd33d81af415279d6ddb518f727")))
+          "e0fa68c7718fffd33d81af415279d6ddb518f727")
+        (introduction
+          (make-channel-introduction
+            "9edb3f66fd807b096b48283debdcddccfea34bad"
+            (openpgp-fingerprint
+              "BBB0 2DDF 2CEA F6A8 0D1D  E643 A2A0 6DF2 A33A 54FA")))))
 @end example
 
 @noindent
@@ -4526,6 +4661,12 @@ produce human-readable output;
 produce a list of channel specifications that can be passed to @command{guix
 pull -C} or installed as @file{~/.config/guix/channels.scm} (@pxref{Invoking
 guix pull});
+@item channels-sans-intro
+like @code{channels}, but omit the @code{introduction} field; use it to
+produce a channel specification suitable for Guix version 1.1.0 or
+earlier---the @code{introduction} field has to do with channel
+authentication (@pxref{Channels, Channel Authentication}) and is not
+supported by these older versions;
 @item json
 @cindex JSON
 produce a list of channel specifications in JSON format;
@@ -4735,9 +4876,10 @@ pack} command allows you to create @dfn{application bundles} that can be
 easily distributed to users who do not run Guix.
 
 @menu
-* Invoking guix environment::  Setting up development environments.
-* Invoking guix pack::         Creating software bundles.
-* The GCC toolchain::          Working with languages supported by GCC.
+* Invoking guix environment::   Setting up development environments.
+* Invoking guix pack::          Creating software bundles.
+* The GCC toolchain::           Working with languages supported by GCC.
+* Invoking guix git authenticate:: Authenticating Git repositories.
 @end menu
 
 @node Invoking guix environment
@@ -5475,6 +5617,68 @@ The package @code{gfortran-toolchain} provides a complete GCC toolchain
 for Fortran development.  For other languages, please use
 @samp{guix search gcc toolchain} (@pxref{guix-search,, Invoking guix package}).
 
+
+@node Invoking guix git authenticate
+@section Invoking @command{guix git authenticate}
+
+The @command{guix git authenticate} command authenticates a Git checkout
+following the same rule as for channels (@pxref{channel-authentication,
+channel authentication}).  That is, starting from a given commit, it
+ensures that all subsequent commits are signed by an OpenPGP key whose
+fingerprint appears in the @file{.guix-authorizations} file of its
+parent commit(s).
+
+You will find this command useful if you maintain a channel.  But in
+fact, this authentication mechanism is useful in a broader context, so
+you might want to use it for Git repositories that have nothing to do
+with Guix.
+
+The general syntax is:
+
+@example
+guix git authenticate @var{commit} @var{signer} [@var{options}@dots{}]
+@end example
+
+By default, this command authenticates the Git checkout in the current
+directory; it outputs nothing and exits with exit code zero on success
+and non-zero on failure.  @var{commit} above denotes the first commit
+where authentication takes place, and @var{signer} is the OpenPGP
+fingerprint of public key used to sign @var{commit}.  Together, they
+form a ``channel introduction'' (@pxref{channel-authentication, channel
+introduction}).  The options below allow you to fine-tune the process.
+
+@table @code
+@item --repository=@var{directory}
+@itemx -r @var{directory}
+Open the Git repository in @var{directory} instead of the current
+directory.
+
+@item --keyring=@var{reference}
+@itemx -k @var{reference}
+Load OpenPGP keyring from @var{reference}, the reference of a branch
+such as @code{origin/keyring} or @code{my-keyring}.  The branch must
+contain OpenPGP public keys in @file{.key} files, either in binary form
+or ``ASCII-armored''.  By default the keyring is loaded from the branch
+named @code{keyring}.
+
+@item --stats
+Display commit signing statistics upon completion.
+
+@item --cache-key=@var{key}
+Previously-authenticated commits are cached in a file under
+@file{~/.cache/guix/authentication}.  This option forces the cache to be
+stored in file @var{key} in that directory.
+
+@item --historical-authorizations=@var{file}
+By default, any commit whose parent commit(s) lack the
+@file{.guix-authorizations} file is considered inauthentic.  In
+contrast, this option considers the authorizations in @var{file} for any
+commit that lacks @file{.guix-authorizations}.  The format of @var{file}
+is the same as that of @file{.guix-authorizations}
+(@pxref{channel-authorizations, @file{.guix-authorizations} format}).
+@end table
+
+
 @c *********************************************************************
 @node Programming Interface
 @chapter Programming Interface
@@ -5489,7 +5693,7 @@ turned into concrete build actions.
 Build actions are performed by the Guix daemon, on behalf of users.  In a
 standard setup, the daemon has write access to the store---the
 @file{/gnu/store} directory---whereas users do not.  The recommended
-setup also has the daemon perform builds in chroots, under a specific
+setup also has the daemon perform builds in chroots, under specific
 build users, to minimize interference with the rest of the system.
 
 @cindex derivation
@@ -6607,6 +6811,48 @@ uuid, the package version, and a list of dependencies specified by their name
 and their uuid.
 @end defvr
 
+@defvr {Scheme Variable} maven-build-system
+This variable is exported by @code{(guix build-system maven)}.  It implements
+a build procedure for @uref{https://maven.apache.org, Maven} packages.  Maven
+is a dependency and lifecycle management tool for Java.  A user of Maven
+specifies dependencies and plugins in a @file{pom.xml} file that Maven reads.
+When Maven does not have one of the dependencies or plugins in its repository,
+it will download them and use them to build the package.
+
+The maven build system ensures that maven will not try to download any
+dependency by running in offline mode.  Maven will fail if a dependency is
+missing.  Before running Maven, the @file{pom.xml} (and subprojects) are
+modified to specify the version of dependencies and plugins that match the
+versions available in the guix build environment.  Dependencies and plugins
+must be installed in the fake maven repository at @file{lib/m2}, and are
+symlinked into a proper repository before maven is run.  Maven is instructed
+to use that repository for the build and installs built artifacts there.
+Changed files are copied to the @file{lib/m2} directory of the package output.
+
+You can specify a @file{pom.xml} file with the @code{#:pom-file} argument,
+or let the build system use the default @file{pom.xml} file in the sources.
+
+In case you need to specify a dependency's version manually, you can use the
+@code{#:local-packages} argument.  It takes an association list where the key
+is the groupId of the package and its value is an association list where the
+key is the artifactId of the package and its value is the version you want to
+override in the @file{pom.xml}.
+
+Some packages use dependencies or plugins that are not useful at runtime nor
+at build time in Guix.  You can alter the @file{pom.xml} file to remove them
+using the @code{#:exclude} argument.  Its value is an association list where
+the key is the groupId of the plugin or dependency you want to remove, and
+the value is a list of artifactId you want to remove.
+
+You can override the default @code{jdk} and @code{maven} packages with the
+corresponding argument, @code{#:jdk} and @code{#:maven}.
+
+The @code{#:maven-plugins} argument is a list of maven plugins used during
+the build, with the same format as the @code{inputs} fields of the package
+declaration.  Its default value is @code{(default-maven-plugins)} which is
+also exported.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
@@ -9178,7 +9424,7 @@ store.
 @section Invoking @command{guix hash}
 
 @cindex @command{guix hash}
-The @command{guix hash} command computes the SHA256 hash of a file.
+The @command{guix hash} command computes the hash of a file.
 It is primarily a convenience tool for anyone contributing to the
 distribution: it computes the cryptographic hash of a file, which can be
 used in the definition of a package (@pxref{Defining Packages}).
@@ -9808,6 +10054,8 @@ list of updaters).  Currently, @var{updater} may be one of:
 @table @code
 @item gnu
 the updater for GNU packages;
+@item savannah
+the updater for packages hosted at @uref{https://savannah.gnu.org, Savannah};
 @item gnome
 the updater for GNOME packages;
 @item kde
@@ -13602,12 +13850,14 @@ illustrates that.
         (with-imported-modules (source-module-closure
                                 '((guix build utils)))
           #~(begin
-              (define %min-level 20)
               (use-modules (guix build utils)
                            (ice-9 popen)
                            (ice-9 regex)
                            (ice-9 textual-ports)
                            (srfi srfi-2))
+
+              (define %min-level 20)
+
               (setenv "LC_ALL" "C")     ;ensure English output
               (and-let* ((input-pipe (open-pipe*
                                       OPEN_READ
@@ -14052,6 +14302,9 @@ It takes the following parameters:
 @item @code{wpa-supplicant} (default: @code{wpa-supplicant})
 The WPA Supplicant package to use.
 
+@item @code{requirement} (default: @code{'(user-processes dbus-system loopback syslogd)}
+List of services that should be started before WPA Supplicant starts.
+
 @item @code{dbus?} (default: @code{#t})
 Whether to listen for requests on D-Bus.
 
@@ -15335,7 +15588,7 @@ auto-login session.
 @cindex Xorg, configuration
 @deftp {Data Type} xorg-configuration
 This data type represents the configuration of the Xorg graphical display
-server.  Note that there is not Xorg service; instead, the X server is started
+server.  Note that there is no Xorg service; instead, the X server is started
 by a ``display manager'' such as GDM, SDDM, and SLiM.  Thus, the configuration
 of these display managers aggregates an @code{xorg-configuration} record.
 
@@ -24775,6 +25028,650 @@ the @code{--snapshot} flag using something along these lines:
           (options '("--hda"))))
 @end lisp
 
+@subsubheading Ganeti
+
+@cindex ganeti
+
+@quotation Note
+This service is considered experimental.  Configuration options may be changed
+in a backwards-incompatible manner, and not all features have been thorougly
+tested.  Users of this service are encouraged to share their experience at
+@email{guix-devel@@gnu.org}.
+@end quotation
+
+Ganeti is a virtual machine management system.  It is designed to keep virtual
+machines running on a cluster of servers even in the event of hardware failures,
+and to make maintenance and recovery tasks easy.  It consists of multiple
+services which are described later in this section.  In addition to the Ganeti
+service, you will need the OpenSSH service (@pxref{Networking Services,
+@code{openssh-service-type}}), and update the @file{/etc/hosts} file
+(@pxref{operating-system Reference, @code{hosts-file}}) with the cluster name
+and address (or use a DNS server).
+
+All nodes participating in a Ganeti cluster should have the same Ganeti and
+@file{/etc/hosts} configuration.  Here is an example configuration for a Ganeti
+cluster node that supports multiple storage backends, and installs the
+@code{debootstrap} and @code{guix} @dfn{OS providers}:
+
+@lisp
+(use-package-modules virtualization)
+(use-service-modules base ganeti networking ssh)
+(operating-system
+  ;; @dots{}
+  (host-name "node1")
+  (hosts-file (plain-file "hosts" (format #f "
+127.0.0.1       localhost
+::1             localhost
+
+192.168.1.200   ganeti.example.com
+192.168.1.201   node1.example.com node1
+192.168.1.202   node2.example.com node2
+")))
+
+  ;; Install QEMU so we can use KVM-based instances, and LVM, DRBD and Ceph
+  ;; in order to use the "plain", "drbd" and "rbd" storage backends.
+  (packages (append (map specification->package
+                         '("qemu" "lvm2" "drbd-utils" "ceph"
+                           ;; Add the debootstrap and guix OS providers.
+                           "ganeti-instance-guix" "ganeti-instance-debootstrap"))
+                    %base-packages))
+  (services
+   (append (list (static-networking-service "eth0" "192.168.1.201"
+                                            #:netmask "255.255.255.0"
+                                            #:gateway "192.168.1.254"
+                                            #:name-servers '("192.168.1.252"
+                                                             "192.168.1.253"))
+
+                 ;; Ganeti uses SSH to communicate between nodes.
+                 (service openssh-service-type
+                          (openssh-configuration
+                           (permit-root-login 'without-password)))
+
+                 (service ganeti-service-type
+                          (ganeti-configuration
+                           ;; This list specifies allowed file system paths
+                           ;; for storing virtual machine images.
+                           (file-storage-paths '("/srv/ganeti/file-storage"))
+                           ;; This variable configures a single "variant" for
+                           ;; both Debootstrap and Guix that works with KVM.
+                           (os %default-ganeti-os))))
+           %base-services)))
+@end lisp
+
+Users are advised to read the
+@url{http://docs.ganeti.org/ganeti/master/html/admin.html,Ganeti
+administrators guide} to learn about the various cluster options and
+day-to-day operations.  There is also a
+@url{https://guix.gnu.org/blog/2020/running-a-ganeti-cluster-on-guix/,blog post}
+describing how to configure and initialize a small cluster.
+
+@defvr {Scheme Variable} ganeti-service-type
+This is a service type that includes all the various services that Ganeti
+nodes should run.
+
+Its value is a @code{ganeti-configuration} object that defines the package
+to use for CLI operations, as well as configuration for the various daemons.
+Allowed file storage paths and available guest operating systems are also
+configured through this data type.
+@end defvr
+
+@deftp {Data Type} ganeti-configuration
+The @code{ganeti} service takes the following configuration options:
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use.  It will be installed to the system profile
+and make @command{gnt-cluster}, @command{gnt-instance}, etc available.  Note
+that the value specified here does not affect the other services as each refer
+to a specific @code{ganeti} package (see below).
+
+@item @code{noded-configuration} (default: @code{(ganeti-noded-configuration)})
+@itemx @code{confd-configuration} (default: @code{(ganeti-confd-configuration)})
+@itemx @code{wconfd-configuration} (default: @code{(ganeti-wconfd-configuration)})
+@itemx @code{luxid-configuration} (default: @code{(ganeti-luxid-configuration)})
+@itemx @code{rapi-configuration} (default: @code{(ganeti-rapi-configuration)})
+@itemx @code{kvmd-configuration} (default: @code{(ganeti-kvmd-configuration)})
+@itemx @code{mond-configuration} (default: @code{(ganeti-mond-configuration)})
+@itemx @code{metad-configuration} (default: @code{(ganeti-metad-configuration)})
+@itemx @code{watcher-configuration} (default: @code{(ganeti-watcher-configuration)})
+@itemx @code{cleaner-configuration} (default: @code{(ganeti-cleaner-configuration)})
+
+These options control the various daemons and cron jobs that are distributed
+with Ganeti.  The possible values for these are described in detail below.
+To override a setting, you must use the configuration type for that service:
+
+@lisp
+(service ganeti-service-type
+         (ganeti-configuration
+          (rapi-configuration
+           (ganeti-rapi-configuration
+            (interface "eth1"))))
+          (watcher-configuration
+           (ganeti-watcher-configuration
+            (rapi-ip "10.0.0.1"))))
+@end lisp
+
+@item @code{file-storage-paths} (default: @code{'()})
+List of allowed directories for file storage backend.
+
+@item @code{os} (default: @code{%default-ganeti-os})
+List of @code{<ganeti-os>} records.
+@end table
+
+In essence @code{ganeti-service-type} is shorthand for declaring each service
+individually:
+
+@lisp
+(service ganeti-noded-service-type)
+(service ganeti-confd-service-type)
+(service ganeti-wconfd-service-type)
+(service ganeti-luxid-service-type)
+(service ganeti-kvmd-service-type)
+(service ganeti-mond-service-type)
+(service ganeti-metad-service-type)
+(service ganeti-watcher-service-type)
+(service ganeti-cleaner-service-type)
+@end lisp
+
+Plus a service extension for @code{etc-service-type} that configures the file
+storage backend and OS variants.
+
+@end deftp
+
+@deftp {Data Type} ganeti-os
+This data type is suitable for passing to the @code{os} parameter of
+@code{ganeti-configuration}.  It takes the following parameters:
+
+@table @asis
+@item @code{name}
+The name for this OS provider.  It is only used to specify where the
+configuration ends up.  Setting it to ``debootstrap'' will create
+@file{/etc/ganeti/instance-debootstrap}.
+
+@item @code{extension}
+The file extension for variants of this OS type.  For example
+@file{.conf} or @file{.scm}.
+
+@item @code{variants} (default: @code{'()})
+List of @code{ganeti-os-variant} objects for this OS.
+
+@end table
+@end deftp
+
+@deftp {Data Type} ganeti-os-variant
+This is the data type for a Ganeti OS variant.  It takes the following
+parameters:
+
+@table @asis
+@item @code{name}
+The name of this variant.
+
+@item @code{configuration}
+A configuration file for this variant.
+@end table
+@end deftp
+
+@defvr {Scheme Variable} %default-debootstrap-hooks
+This variable contains hooks to configure networking and the GRUB bootloader.
+@end defvr
+
+@defvr {Scheme Variable} %default-debootstrap-extra-pkgs
+This variable contains a list of packages suitable for a fully-virtualized guest.
+@end defvr
+
+@deftp {Data Type} debootstrap-configuration
+
+This data type creates configuration files suitable for the debootstrap OS provider.
+
+@table @asis
+@item @code{hooks} (default: @code{%default-debootstrap-hooks})
+When not @code{#f}, this must be a G-expression that specifies a directory with
+scripts that will run when the OS is installed.  It can also be a list of
+@code{(name . file-like)} pairs.  For example:
+
+@lisp
+`((99-hello-world . ,(plain-file "#!/bin/sh\necho Hello, World")))
+@end lisp
+
+That will create a directory with one executable named @code{99-hello-world}
+and run it every time this variant is installed.  If set to @code{#f}, hooks
+in @file{/etc/ganeti/instance-debootstrap/hooks} will be used, if any.
+@item @code{proxy} (default: @code{#f})
+Optional HTTP proxy to use.
+@item @code{mirror} (default: @code{#f})
+The Debian mirror.  Typically something like @code{http://ftp.no.debian.org/debian}.
+The default varies depending on the distribution.
+@item @code{arch} (default: @code{#f})
+The dpkg architecture.  Set to @code{armhf} to debootstrap an ARMv7 instance
+on an AArch64 host.  Default is to use the current system architecture.
+@item @code{suite} (default: @code{"stable"})
+When set, this must be a Debian distribution ``suite'' such as @code{buster}
+or @code{focal}.  If set to @code{#f}, the default for the OS provider is used.
+@item @code{extra-pkgs} (default: @code{%default-debootstrap-extra-pkgs})
+List of extra packages that will get installed by dpkg in addition
+to the minimal system.
+@item @code{components} (default: @code{#f})
+When set, must be a list of Debian repository ``components''.  For example
+@code{'("main" "contrib")}.
+@item @code{generate-cache?} (default: @code{#t})
+Whether to automatically cache the generated debootstrap archive.
+@item @code{clean-cache} (default: @code{14})
+Discard the cache after this amount of days.  Use @code{#f} to never
+clear the cache.
+@item @code{partition-style} (default: @code{'msdos})
+The type of partition to create.  When set, it must be one of
+@code{'msdos}, @code{'none} or a string.
+@item @code{partition-alignment} (default: @code{2048})
+Alignment of the partition in sectors.
+@end table
+@end deftp
+
+@deffn {Scheme Procedure} debootstrap-variant @var{name} @var{configuration}
+This is a helper procedure that creates a @code{ganeti-os-variant} record.  It
+takes two parameters: a name and a @code{debootstrap-configuration} object.
+@end deffn
+
+@deffn {Scheme Procedure} debootstrap-os @var{variants}@dots{}
+This is a helper procedure that creates a @code{ganeti-os} record.  It takes
+a list of variants created with @code{debootstrap-variant}.
+@end deffn
+
+@deffn {Scheme Procedure} guix-variant @var{name} @var{configuration}
+This is a helper procedure that creates a @code{ganeti-os-variant} record for
+use with the Guix OS provider.  It takes a name and a G-expression that returns
+a ``file-like'' (@pxref{G-Expressions, file-like objects}) object containing a
+Guix System configuration.
+@end deffn
+
+@deffn {Scheme Procedure} guix-os @var{variants}@dots{}
+This is a helper procedure that creates a @code{ganeti-os} record.  It
+takes a list of variants produced by @code{guix-variant}.
+@end deffn
+
+@defvr {Scheme Variable} %default-debootstrap-variants
+This is a convenience variable to make the debootstrap provider work
+``out of the box'' without users having to declare variants manually.  It
+contains a single debootstrap variant with the default configuration:
+
+@lisp
+(list (debootstrap-variant
+       "default"
+       (debootstrap-configuration)))
+@end lisp
+@end defvr
+
+@defvr {Scheme Variable} %default-guix-variants
+This is a convenience variable to make the Guix OS provider work without
+additional configuration.  It creates a virtual machine that has an SSH
+server, a serial console, and authorizes the Ganeti hosts SSH keys.
+
+@lisp
+(list (guix-variant
+       "default"
+       (file-append ganeti-instance-guix
+                    "/share/doc/ganeti-instance-guix/examples/dynamic.scm")))
+@end lisp
+@end defvr
+
+Users can implement support for OS providers unbeknownst to Guix by extending
+the @code{ganeti-os} and @code{ganeti-os-variant} records appropriately.
+For example:
+
+@lisp
+(ganeti-os
+ (name "custom")
+ (extension ".conf")
+ (variants
+  (list (ganeti-os-variant
+         (name "foo")
+         (configuration (plain-file "bar" "this is fine"))))))
+@end lisp
+
+That creates @file{/etc/ganeti/instance-custom/variants/foo.conf} which points
+to a file in the store with contents @code{this is fine}.  It also creates
+@file{/etc/ganeti/instance-custom/variants/variants.list} with contents @code{foo}.
+
+Obviously this may not work for all OS providers out there.  If you find the
+interface limiting, please reach out to @email{guix-devel@@gnu.org}.
+
+The rest of this section documents the various services that are included by
+@code{ganeti-service-type}.
+
+@defvr {Scheme Variable} ganeti-noded-service-type
+@command{ganeti-noded} is the daemon responsible for node-specific functions
+within the Ganeti system.  The value of this service must be a
+@code{ganeti-noded-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-noded-configuration
+This is the configuration for the @code{ganeti-noded} service.
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{port} (default: @code{1811})
+The TCP port on which the node daemon listens for network requests.
+
+@item @code{address} (default: @code{"0.0.0.0"})
+The network address that the daemon will bind to.  The default address means
+bind to all available addresses.
+
+@item @code{interface} (default: @code{#f})
+When this is set, it must be a specific network interface (e.g.@: @code{eth0})
+that the daemon will bind to.
+
+@item @code{max-clients} (default: @code{20})
+This sets a limit on the maximum number of simultaneous client connections
+that the daemon will handle.  Connections above this count are accepted, but
+no responses will be sent until enough connections have closed.
+
+@item @code{ssl?} (default: @code{#t})
+Whether to use SSL/TLS to encrypt network communications.  The certificate
+is automatically provisioned by the cluster and can be rotated with
+@command{gnt-cluster renew-crypto}.
+
+@item @code{ssl-key} (default: @file{"/var/lib/ganeti/server.pem"})
+This can be used to provide a specific encryption key for TLS communications.
+
+@item @code{ssl-cert} (default: @file{"/var/lib/ganeti/server.pem"})
+This can be used to provide a specific certificate for TLS communications.
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+Note that this will leak encryption details to the log files, use with caution.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-confd-service-type
+@command{ganeti-confd} answers queries related to the configuration of a
+Ganeti cluster.  The purpose of this daemon is to have a highly available
+and fast way to query cluster configuration values.  It is automatically
+active on all @dfn{master candidates}.  The value of this service must be a
+@code{ganeti-confd-configuration} object.
+
+@end defvr
+
+@deftp {Data Type} ganeti-confd-configuration
+This is the configuration for the @code{ganeti-confd} service.
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{port} (default: @code{1814})
+The UDP port on which to listen for network requests.
+
+@item @code{address} (default: @code{"0.0.0.0"})
+Network address that the daemon will bind to.
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-wconfd-service-type
+@command{ganeti-wconfd} is the daemon that has authoritative knowledge
+about the cluster configuration and is the only entity that can accept
+changes to it.  All jobs that need to modify the configuration will do so
+by sending appropriate requests to this daemon.  It only runs on the
+@dfn{master node} and will automatically disable itself on other nodes.
+
+The value of this service must be a
+@code{ganeti-wconfd-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-wconfd-configuration
+This is the configuration for the @code{ganeti-wconfd} service.
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{no-voting?} (default: @code{#f})
+The daemon will refuse to start if the majority of cluster nodes does not
+agree that it is running on the master node.  Set to @code{#t} to start
+even if a quorum can not be reached (dangerous, use with caution).
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-luxid-service-type
+@command{ganeti-luxid} is a daemon used to answer queries related to the
+configuration and the current live state of a Ganeti cluster.  Additionally,
+it is the authorative daemon for the Ganeti job queue.   Jobs can be
+submitted via this daemon and it schedules and starts them.
+
+It takes a @code{ganeti-luxid-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-luxid-configuration
+This is the configuration for the @code{ganeti-wconfd} service.
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{no-voting?} (default: @code{#f})
+The daemon will refuse to start if it cannot verify that the majority of
+cluster nodes believes that it is running on the master node.  Set to
+@code{#t} to ignore such checks and start anyway (this can be dangerous).
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-rapi-service-type
+@command{ganeti-rapi} provides a remote API for Ganeti clusters.  It runs on
+the master node and can be used to perform cluster actions programmatically
+via a JSON-based RPC protocol.
+
+Most query operations are allowed without authentication (unless
+@var{require-authentication?} is set), whereas write operations require
+explicit authorization via the @file{/var/lib/ganeti/rapi/users} file.  See
+the @url{http://docs.ganeti.org/ganeti/master/html/rapi.html, Ganeti Remote
+API documentation} for more information.
+
+The value of this service must be a @code{ganeti-rapi-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-rapi-configuration
+This is the configuration for the @code{ganeti-rapi} service.
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{require-authentication?} (default: @code{#f})
+Whether to require authentication even for read-only operations.
+
+@item @code{port} (default: @code{5080})
+The TCP port on which to listen to API requests.
+
+@item @code{address} (default: @code{"0.0.0.0"})
+The network address that the service will bind to.  By default it listens
+on all configured addresses.
+
+@item @code{interface} (default: @code{#f})
+When set, it must specify a specific network interface such as @code{eth0}
+that the daemon will bind to.
+
+@item @code{max-clients} (default: @code{20})
+The maximum number of simultaneous client requests to handle.  Further
+connections are allowed, but no responses are sent until enough connections
+have closed.
+
+@item @code{ssl?} (default: @code{#t})
+Whether to use SSL/TLS encryption on the RAPI port.
+
+@item @code{ssl-key} (default: @file{"/var/lib/ganeti/server.pem"})
+This can be used to provide a specific encryption key for TLS communications.
+
+@item @code{ssl-cert} (default: @file{"/var/lib/ganeti/server.pem"})
+This can be used to provide a specific certificate for TLS communications.
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+Note that this will leak encryption details to the log files, use with caution.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-kvmd-service-type
+@command{ganeti-kvmd} is responsible for determining whether a given KVM
+instance was shut down by an administrator or a user.  Normally Ganeti will
+restart an instance that was not stopped through Ganeti itself.  If the
+cluster option @code{user_shutdown} is true, this daemon monitors the
+@code{QMP} socket provided by QEMU and listens for shutdown events, and
+marks the instance as @dfn{USER_down} instead of @dfn{ERROR_down} when
+it shuts down gracefully by itself.
+
+It takes a @code{ganeti-kvmd-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-kvmd-configuration
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-mond-service-type
+@command{ganeti-mond} is an optional daemon that provides Ganeti monitoring
+functionality.  It is responsible for running data collectors and publish the
+collected information through a HTTP interface.
+
+It takes a @code{ganeti-mond-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-mond-configuration
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{port} (default: @code{1815})
+The port on which the daemon will listen.
+
+@item @code{address} (default: @code{"0.0.0.0"})
+The network address that the daemon will bind to.  By default it binds to all
+available interfaces.
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-metad-service-type
+@command{ganeti-metad} is an optional daemon that can be used to provide
+information about the cluster to instances or OS install scripts.
+
+It takes a @code{ganeti-metad-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-metad-configuration
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{port} (default: @code{80})
+The port on which the daemon will listen.
+
+@item @code{address} (default: @code{#f})
+If set, the daemon will bind to this address only.  If left unset, the behavior
+depends on the cluster configuration.
+
+@item @code{debug?} (default: @code{#f})
+When true, the daemon performs additional logging for debugging purposes.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-watcher-service-type
+@command{ganeti-watcher} is a script designed to run periodically and ensure
+the health of a cluster.  It will automatically restart instances that have
+stopped without Ganetis consent, and repairs DRBD links in case a node has
+rebooted.  It also archives old cluster jobs and restarts Ganeti daemons
+that are not running.  If the cluster parameter @code{ensure_node_health}
+is set, the watcher will also shutdown instances and DRBD devices if the
+node it is running on is declared offline by known master candidates.
+
+It can be paused on all nodes with @command{gnt-cluster watcher pause}.
+
+The service takes a @code{ganeti-watcher-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-watcher-configuration
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for this service.
+
+@item @code{schedule} (default: @code{'(next-second-from (next-minute (range 0 60 5)))})
+How often to run the script.  The default is every five minutes.
+
+@item @code{rapi-ip} (default: @code{#f})
+This option needs to be specified only if the RAPI daemon is configured to use
+a particular interface or address.  By default the cluster address is used.
+
+@item @code{job-age} (default: @code{(* 6 3600)})
+Archive cluster jobs older than this age, specified in seconds.  The default
+is 6 hours.  This keeps @command{gnt-job list} manageable.
+
+@item @code{verify-disks?} (default: @code{#t})
+If this is @code{#f}, the watcher will not try to repair broken DRBD links
+automatically.  Administrators will need to use @command{gnt-cluster verify-disks}
+manually instead.
+
+@item @code{debug?} (default: @code{#f})
+When @code{#t}, the script performs additional logging for debugging purposes.
+
+@end table
+@end deftp
+
+@defvr {Scheme Variable} ganeti-cleaner-service-type
+@command{ganeti-cleaner} is a script designed to run periodically and remove
+old files from the cluster.  This service type controls two @dfn{cron jobs}:
+one intended for the master node that permanently purges old cluster jobs,
+and one intended for every node that removes expired X509 certificates, keys,
+and outdated @command{ganeti-watcher} information.  Like all Ganeti services,
+it is safe to include even on non-master nodes as it will disable itself as
+necessary.
+
+It takes a @code{ganeti-cleaner-configuration} object.
+@end defvr
+
+@deftp {Data Type} ganeti-cleaner-configuration
+
+@table @asis
+@item @code{ganeti} (default: @code{ganeti})
+The @code{ganeti} package to use for the @command{gnt-cleaner} command.
+
+@item @code{master-schedule} (default: @code{"45 1 * * *"})
+How often to run the master cleaning job.  The default is once per day, at
+01:45:00.
+
+@item @code{node-schedule} (default: @code{"45 2 * * *"})
+How often to run the node cleaning job.  The default is once per day, at
+02:45:00.
+
+@end table
+@end deftp
+
 @node Version Control Services
 @subsection Version Control Services
 
@@ -24803,39 +25700,41 @@ access to exported@footnote{By creating the magic file
 Data type representing the configuration for @code{git-daemon-service}.
 
 @table @asis
-@item @code{package} (default: @var{git})
+@item @code{package} (default: @code{git})
 Package object of the Git distributed version control system.
 
-@item @code{export-all?} (default: @var{#f})
+@item @code{export-all?} (default: @code{#f})
 Whether to allow access for all Git repositories, even if they do not
 have the @file{git-daemon-export-ok} file.
 
 @item @code{base-path} (default: @file{/srv/git})
 Whether to remap all the path requests as relative to the given path.
-If you run git daemon with @var{(base-path "/srv/git")} on example.com,
-then if you later try to pull @code{git://example.com/hello.git}, git
-daemon will interpret the path as @code{/srv/git/hello.git}.
+If you run @command{git daemon} with @code{(base-path "/srv/git")} on
+@samp{example.com}, then if you later try to pull
+@indicateurl{git://example.com/hello.git}, git daemon will interpret the
+path as @file{/srv/git/hello.git}.
 
-@item @code{user-path} (default: @var{#f})
+@item @code{user-path} (default: @code{#f})
 Whether to allow @code{~user} notation to be used in requests.  When
-specified with empty string, requests to @code{git://host/~alice/foo} is
-taken as a request to access @code{foo} repository in the home directory
-of user @code{alice}.  If @var{(user-path "path")} is specified, the
-same request is taken as a request to access @code{path/foo} repository
-in the home directory of user @code{alice}.
-
-@item @code{listen} (default: @var{'()})
+specified with empty string, requests to
+@indicateurl{git://host/~alice/foo} is taken as a request to access
+@code{foo} repository in the home directory of user @code{alice}.  If
+@code{(user-path "@var{path}")} is specified, the same request is taken
+as a request to access @file{@var{path}/foo} repository in the home
+directory of user @code{alice}.
+
+@item @code{listen} (default: @code{'()})
 Whether to listen on specific IP addresses or hostnames, defaults to
 all.
 
-@item @code{port} (default: @var{#f})
+@item @code{port} (default: @code{#f})
 Whether to listen on an alternative port, which defaults to 9418.
 
-@item @code{whitelist} (default: @var{'()})
+@item @code{whitelist} (default: @code{'()})
 If not empty, only allow access to this list of directories.
 
-@item @code{extra-options} (default: @var{'()})
-Extra options will be passed to @code{git daemon}, please run
+@item @code{extra-options} (default: @code{'()})
+Extra options will be passed to @command{git daemon}, please run
 @command{man git-daemon} for more information.
 
 @end table
@@ -24867,14 +25766,14 @@ Package object of the Git distributed version control system.
 @item @code{git-root} (default: @file{/srv/git})
 Directory containing the Git repositories to expose to the world.
 
-@item @code{export-all?} (default: @var{#f})
+@item @code{export-all?} (default: @code{#f})
 Whether to expose access for all Git repositories in @var{git-root},
 even if they do not have the @file{git-daemon-export-ok} file.
 
-@item @code{uri-path} (default: @file{/git/})
-Path prefix for Git access.  With the default @code{/git/} prefix, this
-will map @code{http://@var{server}/git/@var{repo}.git} to
-@code{/srv/git/@var{repo}.git}.  Requests whose URI paths do not begin
+@item @code{uri-path} (default: @samp{/git/})
+Path prefix for Git access.  With the default @samp{/git/} prefix, this
+will map @indicateurl{http://@var{server}/git/@var{repo}.git} to
+@file{/srv/git/@var{repo}.git}.  Requests whose URI paths do not begin
 with this prefix are not passed on to this Git instance.
 
 @item @code{fcgiwrap-socket} (default: @code{127.0.0.1:9000})
@@ -26619,6 +27518,55 @@ setuid-root (@pxref{Setuid Programs}) such that unprivileged users can invoke
 @command{singularity run} and similar commands.
 @end defvr
 
+@cindex rshiny
+@subsubheading R-Shiny service
+
+The @code{(gnu services science)} module provides the following service.
+
+@defvr {Scheme Variable} rshiny-service-type
+
+This is a type of service which is used to run a webapp created with
+@code{r-shiny}.  This service sets the @code{R_LIBS_USER} environment
+variable and runs the provided script to call @code{runApp}.
+
+@deftp {Data Type} rshiny-configuration
+This is the data type representing the configuration of rshiny.
+
+@table @asis
+
+@item @code{package} (default: @code{r-shiny})
+The package to use.
+
+@item @code{binary} (defaunlt @code{"rshiny"})
+The name of the binary or shell script located at @code{package/bin/} to
+run when the service is run.
+
+The common way to create this file is as follows:
+
+@lisp
+@dots{}
+(let* ((out       (assoc-ref %outputs "out"))
+       (targetdir (string-append out "/share/" ,name))
+       (app       (string-append out "/bin/" ,name))
+       (Rbin      (string-append (assoc-ref %build-inputs "r-min")
+                                 "/bin/Rscript")))
+@dots{}
+  (mkdir-p (string-append out "/bin"))
+  (call-with-output-file app
+    (lambda (port)
+      (format port
+"#!~a
+library(shiny)
+setwd(\"~a\")
+runApp(launch.browser=0, port=4202)~%\n"
+      Rbin targetdir)))
+@dots{}
+@end lisp
+
+@end table
+@end deftp
+@end defvr
+
 @cindex Nix
 @subsubheading Nix service
 
@@ -26660,6 +27608,27 @@ $ source /run/current-system/profile/etc/profile.d/nix.sh
 
 @end defvr
 
+@deftp {Data Type} nix-configuration
+This data type represents the configuration of the Nix daemon.
+
+@table @asis
+@item @code{nix} (default: @code{nix})
+The Nix package to use.
+
+@item @code{sandbox} (default: @code{#t})
+Specifies whether builds are sandboxed by default.
+
+@item @code{build-sandbox-items} (default: @code{'()})
+This is a list of strings or objects appended to the
+@code{build-sandbox-items} field of the configuration file.
+
+@item @code{extra-config} (default: @code{'()})
+This is a list of strings or objects appended to the configuration file.
+It is used to pass extra text to be added verbatim to the configuration
+file.
+@end table
+@end deftp
+
 @node Setuid Programs
 @section Setuid Programs
 
@@ -27426,11 +28395,16 @@ an older system generation at boot time should you need it.
 Upon completion, the new system is deployed under
 @file{/run/current-system}.  This directory contains @dfn{provenance
 meta-data}: the list of channels in use (@pxref{Channels}) and
-@var{file} itself, when available.  This information is useful should
-you later want to inspect how this particular generation was built.
+@var{file} itself, when available.  You can view it by running:
+
+@example
+guix system describe
+@end example
 
-In fact, assuming @var{file} is self-contained, you can later rebuild
-generation @var{n} of your operating system with:
+This information is useful should you later want to inspect how this
+particular generation was built.  In fact, assuming @var{file} is
+self-contained, you can later rebuild generation @var{n} of your
+operating system with:
 
 @example
 guix time-machine \
@@ -27444,6 +28418,12 @@ system is not just a binary artifact: @emph{it carries its own source}.
 @xref{Service Reference, @code{provenance-service-type}}, for more
 information on provenance tracking.
 
+By default, @command{reconfigure} @emph{prevents you from downgrading
+your system}, which could (re)introduce security vulnerabilities and
+also cause problems with ``stateful'' services such as database
+management systems.  You can override that behavior by passing
+@option{--allow-downgrades}.
+
 @item switch-generation
 @cindex generations
 Switch to an existing system generation.  This action atomically
@@ -27623,7 +28603,7 @@ the device corresponding to a USB stick, one can copy the image to it
 using the following command:
 
 @example
-# dd if=$(guix system disk-image my-os.scm) of=/dev/sdc
+# dd if=$(guix system disk-image my-os.scm) of=/dev/sdc status=progress
 @end example
 
 When using @code{docker-image}, a Docker image is produced.  Guix builds
@@ -27770,6 +28750,22 @@ appear in the @code{operating-system} declaration actually exist
 needed at boot time are listed in @code{initrd-modules} (@pxref{Initial
 RAM Disk}).  Passing this option skips these tests altogether.
 
+@item --allow-downgrades
+Instruct @command{guix system reconfigure} to allow system downgrades.
+
+By default, @command{reconfigure} prevents you from downgrading your
+system.  It achieves that by comparing the provenance info of your
+system (shown by @command{guix system describe}) with that of your
+@command{guix} command (shown by @command{guix describe}).  If the
+commits for @command{guix} are not descendants of those used for your
+system, @command{guix system reconfigure} errors out.  Passing
+@option{--allow-downgrades} allows you to bypass these checks.
+
+@quotation Note
+Make sure you understand its security implications before using
+@option{--allow-downgrades}.
+@end quotation
+
 @cindex on-error
 @cindex on-error strategy
 @cindex error strategy