services: Introduce extensible services.
This patch rewrites GuixSD services to make them extensible. * gnu-system.am (GNU_SYSTEM_MODULES): Add gnu/services/dbus.scm. * gnu/services.scm (<service>): Replace with new record type. (<service-extension>, <service-type>): New record types. (write-service-type, compute-boot-script, second-argument): New procedures. (%boot-service, boot-service-type): New variables. (file-union, directory-union, modprobe-wrapper, activation-service->script, activation-script, gexps->activation-gexp): New procedures. (activation-service-type, %activation-service): New variables. (etc-directory, files->etc-directory, etc-service): New procedures. (etc-service-type, setuid-program-service, firmware-service-type): New variables. (firmware->activation-gexp): New procedure. (&service-error, &missing-target-service-error, &ambiguous-target-service-error): New condition types. (service-back-edges, fold-services): New procedures. * gnu/services/avahi.scm (<avahi-configuration>): New record type. (configuration-file): Replace keyword parameters with a single 'config' parameter. (%avahi-accounts, %avahi-activation, avahi-service-type): New variables. (avahi-dmd-service): New procedure. (avahi-service): Rewrite using 'service' and 'avahi-configuration'. * gnu/services/base.scm (%root-file-system-dmd-service, root-file-system-service-type): New variables. (root-file-system-service): Use them. (file-system->dmd-service-name): New procedure. (file-system-service-type): New variable. (file-system-service): Use it. Replace keyword parameters with a single 'file-system' object. (user-unmount-service-type): New variable. (user-unmount-service): Use it. (user-processes-service-type): New variable. (user-processes-service): Use it. (host-name-service-type): New variable. (host-name-service): Use it. (console-keymap-service-type): New variable. (console-keymap-service): Use it. (console-font-service-type): New variable. (console-font-service): Use it. (mingetty-pam-service, mingetty-dmd-service): New procedures. (mingetty-service-type): New variable. (mingetty-service): Use it. (nscd-dmd-service): New procedure. (nscd-activation, nscd-service-type): New variables. (nscd-service): Use the latter. (syslog-service-type): New variable. (syslog-service): Use it. (<guix-configuration>): New record type. (%default-guix-configuration): New variable. (guix-dmd-service, guix-accounts, guix-activation): New procedures. (guix-service-type): New variable. (guix-service): Replace list of keyword parameters with a single 'config' parameter. Rewrite using 'service'. (<udev-configuration>): New record type. (udev-dmd-service): New procedure. (udev-service-type): New variable. (udev-service): Use it. (device-mapping-service-type): New variable. (device-mapping-service): Use it. (swap-service-type): New variable. (swap-service): Use it. * gnu/services/databases.scm (<postgresql-configuration>): New record type. (%postgresql-accounts, postgresql-activation): New variables. (postgresql-dmd-service): New procedure. (postgresql-service): Rewrite using 'service' and 'postgresql-configuration'. * gnu/services/dbus.scm: New file. * gnu/services/desktop.scm (dbus-configuration-directory, dbus-service): Remove. (wrapped-dbus-service): New procedure. (<upower-configuration>): New record type. (upower-configuration-file): Replace keyword parameters with single <upower-configuration> parameter. (%upower-accounts, %upower-activation): New variables. (upower-dbus-service, upower-dmd-service): New procedures. (upower-service-type): New variable. (upower-service): Rewrite using 'service' and 'upower-configuration'. (%colord-activation, %colord-accounts): New variables. (colord-dmd-service): New procedure. (colord-service-type): New variable. (colord-service): Rewrite using 'service'. (<geoclue-configuration>): New record type. (geoclue-configuration-file): Replace keyword parameters with a single 'config' parameter. (geoclue-dbus-service, geoclue-dmd-service): New procedures. (%geoclue-accounts, geoclue-service-type): New variables. (geoclue-service): Rewrite using 'service' and 'geoclue-configuration'. (%polkit-accounts, %polkit-pam-services, polkit-service-type): New variables. (polkit-dmd-service): New procedure. (polkit-service): Rewrite using 'service'. (<elogind-configuration>)[elogind]: New field. (elogind-dmd-service): New procedure. (elogind-service-type): New variable. (elogind-service): Rewrite using 'service'. (%desktop-services): Remove argument to 'dbus-service'. Remove 'map' over %BASE-SERVICES. * gnu/services/dmd.scm (dmd-boot-gexp): New procedure. (dmd-root-service-type, %dmd-root-service): New variables. (dmd-service-type): New macro. (<dmd-service>): New record type. * gnu/services/lirc.scm (<lirc-configuration>): New record type. (%lirc-activation): New variable. (lirc-dmd-service): New procedure. (lirc-service-type): New variable. (lirc-service): Rewrite using 'service' and 'lirc-configuration'. * gnu/services/networking.scm (<static-networking>): New record type. (static-networking-service-type): New variable. (static-networking-service): Rewrite using 'service' and 'static-networking'. (dhcp-client-service-type): New variable. (dhcp-client-service): Rewrite using 'service'. (<ntp-configuration>): New record type. (ntp-dmd-service): New procedure. (ntp-service-type): New variable. (ntp-service): New procedure. (%tor-accounts, tor-service-type): New variable. (tor-dmd-service): New procedure. (tor-service): Rewrite using 'service'. (<bitlbee-configuration>): New record type. (bitlbee-dmd-service): New procedure. (%bitlbee-accounts, %bitlbee-activation, bitlbee-service-type): New variables. (bitlbee-service): Rewrite using 'service'. (%wicd-activation): New variable. (wicd-dmd-service): New procedure. (wicd-service-type): New variable. (wicd-service): Rewrite using 'service'. * gnu/services/ssh.scm (<lsh-configuration>): New record type. (activation): Rename to... (lsh-initialization): ... this. (lsh-activation, lsh-dmd-service, lsh-pam-services): New procedures. (lsh-service-type): New variable. (lsh-service): Rewrite using 'service' and 'lsh-configuration'. * gnu/services/web.scm (<nginx-configuration>): New record type. (%nginx-accounts): New variable. (nginx-activation, nginx-dmd-service): New procedures. (nginx-service-type): New variable. (nginx-service): Rewrite using 'service' and 'nginx-configuration'. * gnu/services/xorg.scm (<slim-configuration>): New record type. (slim-pam-service, slim-dmd-service): New procedures. (slim-service-type): New variable. (slim-service): Rewrite using 'service' and 'slim-configuration'. * gnu/system.scm (file-union): Remove. (other-file-system-services): Adjust to new 'file-system-service' signature. (essential-services): Add #:container? parameter. Add %DMD-ROOT-SERVICE, %ACTIVATION-SERVICE, and calls to 'pam-root-service', 'account-service', 'operating-system-etc-service', and a SETUID-PROGRAM-SERVICE instance. (operating-system-services): Pass #:container? to 'essential-services. (etc-directory): Remove. (operating-system-etc-service): New procedure. Rewrite as a call to 'etc-service'. (operating-system-accounts): Change to not return accounts required by services. (operating-system-etc-directory): Rewrite as a call to 'fold-services' and 'etc-directory'. (user-group->gexp, user-account->gexp, modprobe-wrapper): Remove. (operating-system-activation-script): Rewrite as a call to 'fold-services' and 'activation-service->script'. (operating-system-boot-script): Likewise. (operating-system-derivation): Add call to 'lower-object'. (emacs-site-file, emacs-site-directory, shells-file): Change to use 'computed-file' and 'scheme-file' instead of the monadic procedures. * gnu/system/install.scm (cow-store-service-type): New variable. (cow-store-service): Rewrite using 'service'. (/etc/configuration-files): New procedure. (configuration-template-service-type, %configuration-template-service): New variables. (configuration-template-service): Remove. (installation-services): Adjust accordingly. Adjust argument to 'guix-service'. * gnu/system/linux.scm (/etc-entry, pam-root-service): New procedures. (pam-root-service-type): New variable. * gnu/system/shadow.scm (user-group->gexp, user-account->gexp, account-activation, etc-skel, account-service): New procedures. (account-service-type): New variable. * tests/services.scm: New file. * doc/guix.texi (Base Services, Desktop Services): Adjust accordingly. (Defining Services): Rewrite. * doc/images/service-graph.dot: New file. * doc.am (DOT_FILES): Add it. * po/guix/POTFILES.in: Add gnu/services.scm.master
parent
e79467f63a
commit
0adfe95a3e
|
@ -129,3 +129,6 @@ GTAGS
|
||||||
/doc/images/coreutils-bag-graph.png
|
/doc/images/coreutils-bag-graph.png
|
||||||
/doc/images/coreutils-graph.png
|
/doc/images/coreutils-graph.png
|
||||||
/doc/images/coreutils-size-map.eps
|
/doc/images/coreutils-size-map.eps
|
||||||
|
/doc/images/service-graph.png
|
||||||
|
/doc/images/service-graph.eps
|
||||||
|
/doc/images/service-graph.pdf
|
||||||
|
|
|
@ -219,6 +219,7 @@ SCM_TESTS = \
|
||||||
tests/size.scm \
|
tests/size.scm \
|
||||||
tests/graph.scm \
|
tests/graph.scm \
|
||||||
tests/file-systems.scm \
|
tests/file-systems.scm \
|
||||||
|
tests/services.scm \
|
||||||
tests/containers.scm
|
tests/containers.scm
|
||||||
|
|
||||||
if HAVE_GUILE_JSON
|
if HAVE_GUILE_JSON
|
||||||
|
|
3
doc.am
3
doc.am
|
@ -22,7 +22,8 @@ info_TEXINFOS = doc/guix.texi
|
||||||
DOT_FILES = \
|
DOT_FILES = \
|
||||||
doc/images/bootstrap-graph.dot \
|
doc/images/bootstrap-graph.dot \
|
||||||
doc/images/coreutils-graph.dot \
|
doc/images/coreutils-graph.dot \
|
||||||
doc/images/coreutils-bag-graph.dot
|
doc/images/coreutils-bag-graph.dot \
|
||||||
|
doc/images/service-graph.dot
|
||||||
|
|
||||||
DOT_VECTOR_GRAPHICS = \
|
DOT_VECTOR_GRAPHICS = \
|
||||||
$(DOT_FILES:%.dot=%.eps) \
|
$(DOT_FILES:%.dot=%.eps) \
|
||||||
|
|
467
doc/guix.texi
467
doc/guix.texi
|
@ -182,6 +182,13 @@ Services
|
||||||
* Web Services:: Web servers.
|
* Web Services:: Web servers.
|
||||||
* Various Services:: Other services.
|
* Various Services:: Other services.
|
||||||
|
|
||||||
|
Defining Services
|
||||||
|
|
||||||
|
* Service Composition:: The model for composing services.
|
||||||
|
* Service Types and Services:: Types and services.
|
||||||
|
* Service Reference:: API reference.
|
||||||
|
* dmd Services:: A particular type of service.
|
||||||
|
|
||||||
Packaging Guidelines
|
Packaging Guidelines
|
||||||
|
|
||||||
* Software Freedom:: What may go into the distribution.
|
* Software Freedom:: What may go into the distribution.
|
||||||
|
@ -5899,23 +5906,41 @@ Return a service that runs @code{syslogd}. If configuration file name
|
||||||
settings.
|
settings.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} guix-service [#:guix guix] @
|
@anchor{guix-configuration-type}
|
||||||
[#:builder-group "guixbuild"] [#:build-accounts 10] @
|
@deftp {Data Type} guix-configuration
|
||||||
[#:authorize-hydra-key? #t] [#:use-substitutes? #t] @
|
This data type represents the configuration of the Guix build daemon.
|
||||||
[#:extra-options '()]
|
@xref{Invoking guix-daemon}, for more information.
|
||||||
Return a service that runs the build daemon from @var{guix}, and has
|
|
||||||
@var{build-accounts} user accounts available under @var{builder-group}.
|
|
||||||
|
|
||||||
When @var{authorize-hydra-key?} is true, the @code{hydra.gnu.org} public key
|
@table @asis
|
||||||
provided by @var{guix} is authorized upon activation, meaning that substitutes
|
@item @code{guix} (default: @var{guix})
|
||||||
from @code{hydra.gnu.org} are used by default.
|
The Guix package to use.
|
||||||
|
|
||||||
If @var{use-substitutes?} is false, the daemon is run with
|
@item @code{build-group} (default: @code{"guixbuild"})
|
||||||
@option{--no-substitutes} (@pxref{Invoking guix-daemon,
|
Name of the group for build user accounts.
|
||||||
@option{--no-substitutes}}).
|
|
||||||
|
|
||||||
Finally, @var{extra-options} is a list of additional command-line options
|
@item @code{build-accounts} (default: @code{10})
|
||||||
passed to @command{guix-daemon}.
|
Number of build user accounts to create.
|
||||||
|
|
||||||
|
@item @code{authorize-key?} (default: @code{#t})
|
||||||
|
Whether to authorize the substitute key for @code{hydra.gnu.org}
|
||||||
|
(@pxref{Substitutes}).
|
||||||
|
|
||||||
|
@item @code{use-substitutes?} (default: @code{#t})
|
||||||
|
Whether to use substitutes.
|
||||||
|
|
||||||
|
@item @code{extra-options} (default: @code{'()})
|
||||||
|
List of extra command-line options for @command{guix-daemon}.
|
||||||
|
|
||||||
|
@item @code{lsof} (default: @var{lsof})
|
||||||
|
@itemx @code{lsh} (default: @var{lsh})
|
||||||
|
The lsof and lsh packages to use.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} guix-service @var{config}
|
||||||
|
Return a service that runs the Guix build daemon according to
|
||||||
|
@var{config}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} udev-service [#:udev udev]
|
@deffn {Scheme Procedure} udev-service [#:udev udev]
|
||||||
|
@ -6179,11 +6204,10 @@ The @var{%desktop-services} variable can be used as the @code{services}
|
||||||
field of an @code{operating-system} declaration (@pxref{operating-system
|
field of an @code{operating-system} declaration (@pxref{operating-system
|
||||||
Reference, @code{services}}).
|
Reference, @code{services}}).
|
||||||
|
|
||||||
The actual service definitions provided by @code{(gnu services desktop)}
|
The actual service definitions provided by @code{(gnu services dbus)}
|
||||||
are described below.
|
and @code{(gnu services desktop)} are described below.
|
||||||
|
|
||||||
@deffn {Scheme Procedure} dbus-service @var{services} @
|
@deffn {Scheme Procedure} dbus-service [#:dbus @var{dbus}] [#:services '()]
|
||||||
[#:dbus @var{dbus}]
|
|
||||||
Return a service that runs the ``system bus'', using @var{dbus}, with
|
Return a service that runs the ``system bus'', using @var{dbus}, with
|
||||||
support for @var{services}.
|
support for @var{services}.
|
||||||
|
|
||||||
|
@ -6197,8 +6221,7 @@ and policy files. For example, to allow avahi-daemon to use the system bus,
|
||||||
@var{services} must be equal to @code{(list avahi)}.
|
@var{services} must be equal to @code{(list avahi)}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} elogind-service @
|
@deffn {Scheme Procedure} elogind-service [#:config @var{config}]
|
||||||
[#:elogind @var{elogind}] [#:config @var{config}]
|
|
||||||
Return a service that runs the @code{elogind} login and
|
Return a service that runs the @code{elogind} login and
|
||||||
seat management daemon. @uref{https://github.com/andywingo/elogind,
|
seat management daemon. @uref{https://github.com/andywingo/elogind,
|
||||||
Elogind} exposes a D-Bus interface that can be used to know which users
|
Elogind} exposes a D-Bus interface that can be used to know which users
|
||||||
|
@ -6957,54 +6980,378 @@ build users.
|
||||||
@node Defining Services
|
@node Defining Services
|
||||||
@subsection Defining Services
|
@subsection Defining Services
|
||||||
|
|
||||||
The @code{(gnu services @dots{})} modules define several procedures that allow
|
The previous sections how the available services and how one can combine
|
||||||
users to declare the operating system's services (@pxref{Using the
|
them in an @code{operating-system} declaration. But how do we define
|
||||||
Configuration System}). These procedures are @emph{monadic
|
them in the first place? And what is a service anyway?
|
||||||
procedures}---i.e., procedures that return a monadic value in the store
|
|
||||||
monad (@pxref{The Store Monad}). For examples of such procedures,
|
|
||||||
@xref{Services}.
|
|
||||||
|
|
||||||
@cindex service definition
|
@menu
|
||||||
The monadic value returned by those procedures is a @dfn{service
|
* Service Composition:: The model for composing services.
|
||||||
definition}---a structure as returned by the @code{service} form.
|
* Service Types and Services:: Types and services.
|
||||||
Service definitions specifies the inputs the service depends on, and an
|
* Service Reference:: API reference.
|
||||||
expression to start and stop the service. Behind the scenes, service
|
* dmd Services:: A particular type of service.
|
||||||
definitions are ``translated'' into the form suitable for the
|
@end menu
|
||||||
configuration file of dmd, the init system (@pxref{Services,,, dmd, GNU
|
|
||||||
dmd Manual}).
|
|
||||||
|
|
||||||
As an example, here is what the @code{nscd-service} procedure looks
|
@node Service Composition
|
||||||
like:
|
@subsubsection Service Composition
|
||||||
|
|
||||||
@lisp
|
@cindex services
|
||||||
(define (nscd-service)
|
@cindex daemons
|
||||||
(with-monad %store-monad
|
Here we define a @dfn{service} as, broadly, something that extends the
|
||||||
(return (service
|
operating system's functionality. Often a service is a process---a
|
||||||
(documentation "Run libc's name service cache daemon.")
|
@dfn{daemon}---started when the system boots: a secure shell server, a
|
||||||
(provision '(nscd))
|
Web server, the Guix build daemon, etc. Sometimes a service is a daemon
|
||||||
(activate #~(begin
|
whose execution can be triggered by another daemon---e.g., an FTP server
|
||||||
(use-modules (guix build utils))
|
started by @command{inetd} or a D-Bus service activated by
|
||||||
(mkdir-p "/var/run/nscd")))
|
@command{dbus-daemon}. Occasionally, a service does not map to a
|
||||||
(start #~(make-forkexec-constructor
|
daemon. For instance, the ``account'' service collects user accounts
|
||||||
(string-append #$glibc "/sbin/nscd")
|
and makes sure they exist when the system runs; the ``udev'' service
|
||||||
"-f" "/dev/null" "--foreground"))
|
collects device management rules and makes them available to the eudev
|
||||||
(stop #~(make-kill-destructor))
|
daemon; the @file{/etc} service populates the system's @file{/etc}
|
||||||
(respawn? #f)))))
|
directory.
|
||||||
@end lisp
|
|
||||||
|
GuixSD services are connected by @dfn{extensions}. For instance, the
|
||||||
|
secure shell service @emph{extends} dmd---GuixSD's initialization system,
|
||||||
|
running as PID@tie{}1---by giving it the command lines to start and stop
|
||||||
|
the secure shell daemon (@pxref{Networking Services,
|
||||||
|
@code{lsh-service}}); the UPower service extends the D-Bus service by
|
||||||
|
passing it its @file{.service} specification, and extends the udev
|
||||||
|
service by passing it device management rules (@pxref{Desktop Services,
|
||||||
|
@code{upower-service}}); the Guix daemon service extends dmd by passing
|
||||||
|
it the command lines to start and stop the daemon, and extends the
|
||||||
|
account service by passing it a list of required build user accounts
|
||||||
|
(@pxref{Base Services}).
|
||||||
|
|
||||||
|
All in all, services and their ``extends'' relations form a directed
|
||||||
|
acyclic graph (DAG). If we represent services as boxes and extensions
|
||||||
|
as arrows, a typical system might provide something like this:
|
||||||
|
|
||||||
|
@image{images/service-graph,,5in,Typical service extension graph.}
|
||||||
|
|
||||||
|
At the bottom, we see the @dfn{boot service}, which produces the boot
|
||||||
|
script that is executed at boot time from the initial RAM disk.
|
||||||
|
|
||||||
|
@cindex service types
|
||||||
|
Technically, developers can define @dfn{service types} to express these
|
||||||
|
relations. There can be any number of services of a given type on the
|
||||||
|
system---for instance, a system running two instances of the GNU secure
|
||||||
|
shell server (lsh) has two instances of @var{lsh-service-type}, with
|
||||||
|
different parameters.
|
||||||
|
|
||||||
|
The following section describes the programming interface for service
|
||||||
|
types and services.
|
||||||
|
|
||||||
|
@node Service Types and Services
|
||||||
|
@subsubsection Service Types and Services
|
||||||
|
|
||||||
|
A @dfn{service type} is a node in the DAG described above. Let us start
|
||||||
|
with a simple example, the service type for the Guix build daemon
|
||||||
|
(@pxref{Invoking guix-daemon}):
|
||||||
|
|
||||||
|
@example
|
||||||
|
(define guix-service-type
|
||||||
|
(service-type
|
||||||
|
(name 'guix)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type guix-dmd-service)
|
||||||
|
(service-extension account-service-type guix-accounts)
|
||||||
|
(service-extension activation-service-type guix-activation)))))
|
||||||
|
@end example
|
||||||
|
|
||||||
@noindent
|
@noindent
|
||||||
The @code{activate}, @code{start}, and @code{stop} fields are G-expressions
|
It defines a two things:
|
||||||
(@pxref{G-Expressions}). The @code{activate} field contains a script to
|
|
||||||
run at ``activation'' time; it makes sure that the @file{/var/run/nscd}
|
|
||||||
directory exists before @command{nscd} is started.
|
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
A name, whose sole purpose is to make inspection and debugging easier.
|
||||||
|
|
||||||
|
@item
|
||||||
|
A list of @dfn{service extensions}, where each extension designates the
|
||||||
|
target service type and a procedure that, given the service's
|
||||||
|
parameters, returns a list of object to extend the service of that type.
|
||||||
|
|
||||||
|
Every service type has at least one service extension. The only
|
||||||
|
exception is the @dfn{boot service type}, which is the ultimate service.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
In this example, @var{guix-service-type} extends three services:
|
||||||
|
|
||||||
|
@table @var
|
||||||
|
@item dmd-root-service-type
|
||||||
|
The @var{guix-dmd-service} procedure defines how the dmd service is
|
||||||
|
extended. Namely, it returns a @code{<dmd-service>} object that defines
|
||||||
|
how @command{guix-daemon} is started and stopped (@pxref{dmd Services}).
|
||||||
|
|
||||||
|
@item account-service-type
|
||||||
|
This extension for this service is computed by @var{guix-accounts},
|
||||||
|
which returns a list of @code{user-group} and @code{user-account}
|
||||||
|
objects representing the build user accounts (@pxref{Invoking
|
||||||
|
guix-daemon}).
|
||||||
|
|
||||||
|
@item activation-service-type
|
||||||
|
Here @var{guix-activation} is a procedure that returns a gexp, which is
|
||||||
|
a code snippet to run at ``activation time''---e.g., when the service is
|
||||||
|
booted.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
A service of this type is instantiated like this:
|
||||||
|
|
||||||
|
@example
|
||||||
|
(service guix-service-type
|
||||||
|
(guix-configuration
|
||||||
|
(build-accounts 5)
|
||||||
|
(use-substitutes? #f)))
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The second argument to the @code{service} form is a value representing
|
||||||
|
the parameters of this specific service instance.
|
||||||
|
@xref{guix-configuration-type, @code{guix-configuration}}, for
|
||||||
|
information about the @code{guix-configuration} data type.
|
||||||
|
|
||||||
|
@var{guix-service-type} is quite simple because it extends other
|
||||||
|
services but is not extensible itself.
|
||||||
|
|
||||||
|
@c @subsubsubsection Extensible Service Types
|
||||||
|
|
||||||
|
The service type for an @emph{extensible} service looks like this:
|
||||||
|
|
||||||
|
@example
|
||||||
|
(define udev-service-type
|
||||||
|
(service-type (name 'udev)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
udev-dmd-service)))
|
||||||
|
|
||||||
|
(compose concatenate) ;concatenate the list of rules
|
||||||
|
(extend (lambda (config rules)
|
||||||
|
(match config
|
||||||
|
(($ <udev-configuration> udev initial-rules)
|
||||||
|
(udev-configuration
|
||||||
|
(udev udev) ;the udev package to use
|
||||||
|
(rules (append initial-rules rules)))))))))
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This is the service type for the
|
||||||
|
@uref{https://wiki.gentoo.org/wiki/Project:Eudev, eudev device
|
||||||
|
management daemon}. Compared to the previous example, in addition to an
|
||||||
|
extension of @var{dmd-root-service-type}, we see two new fields:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item compose
|
||||||
|
This is the procedure to @dfn{compose} the list of extensions to
|
||||||
|
services of this type.
|
||||||
|
|
||||||
|
Services can extend the udev service by passing it lists of rules; we
|
||||||
|
compose those extensions simply by concatenating them.
|
||||||
|
|
||||||
|
@item extend
|
||||||
|
This procedure defines how the service's value is @dfn{extended} with
|
||||||
|
the composition of the extensions.
|
||||||
|
|
||||||
|
Udev extensions are composed into a list of rules, but the udev service
|
||||||
|
value is itself a @code{<udev-configuration>} record. So here, we
|
||||||
|
extend that record by appending the list of rules is contains to the
|
||||||
|
list of contributed rules.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
There can be only one instance of an extensible service type such as
|
||||||
|
@var{udev-service-type}. If there were more, the
|
||||||
|
@code{service-extension} specifications would be ambiguous.
|
||||||
|
|
||||||
|
Still here? The next section provides a reference of the programming
|
||||||
|
interface for services.
|
||||||
|
|
||||||
|
@node Service Reference
|
||||||
|
@subsubsection Service Reference
|
||||||
|
|
||||||
|
We have seen an overview of service types (@pxref{Service Types and
|
||||||
|
Services}). This section provides a reference on how to manipulate
|
||||||
|
services and service types. This interface is provided by the
|
||||||
|
@code{(gnu services)} module.
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} service @var{type} @var{value}
|
||||||
|
Return a new service of @var{type}, a @code{<service-type>} object (see
|
||||||
|
below.) @var{value} can be any object; it represents the parameters of
|
||||||
|
this particular service instance.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} service? @var{obj}
|
||||||
|
Return true if @var{obj} is a service.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} service-kind @var{service}
|
||||||
|
Return the type of @var{service}---i.e., a @code{<service-type>} object.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} service-parameters @var{service}
|
||||||
|
Return the value associated with @var{service}. It represents its
|
||||||
|
parameters.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
Here is an example of how a service is created and manipulated:
|
||||||
|
|
||||||
|
@example
|
||||||
|
(define s
|
||||||
|
(service nginx-service-type
|
||||||
|
(nginx-configuration
|
||||||
|
(nginx nginx)
|
||||||
|
(log-directory log-directory)
|
||||||
|
(run-directory run-directory)
|
||||||
|
(file config-file))))
|
||||||
|
|
||||||
|
(service? s)
|
||||||
|
@result{} #t
|
||||||
|
|
||||||
|
(eq? (service-kind s) nginx-service-type)
|
||||||
|
@result{} #t
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@deftp {Data Type} service-type
|
||||||
|
@cindex service type
|
||||||
|
This is the representation of a @dfn{service type} (@pxref{Service Types
|
||||||
|
and Services}).
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{name}
|
||||||
|
This is a symbol, used only to simplify inspection and debugging.
|
||||||
|
|
||||||
|
@item @code{extensions}
|
||||||
|
A non-empty list of @code{<service-extension>} objects (see below.)
|
||||||
|
|
||||||
|
@item @code{compose} (default: @code{#f})
|
||||||
|
If this is @code{#f}, then the service type denotes services that cannot
|
||||||
|
be extended---i.e., services that do not receive ``values'' from other
|
||||||
|
services.
|
||||||
|
|
||||||
|
Otherwise, it must be a one-argument procedure. The procedure is called
|
||||||
|
by @code{fold-services} and is passed a list of values collected from
|
||||||
|
extensions. It must return a value that is a valid parameter value for
|
||||||
|
the service instance.
|
||||||
|
|
||||||
|
@item @code{extend} (default: @code{#f})
|
||||||
|
If this is @code{#f}, services of this type cannot be extended.
|
||||||
|
|
||||||
|
Otherwise, it must be a two-argument procedure: @code{fold-services}
|
||||||
|
calls it, passing it the service's initial value as the first argument
|
||||||
|
and the result of applying @code{compose} to the extension values as the
|
||||||
|
second argument.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@xref{Service Types and Services}, for examples.
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} service-extension @var{target-type} @
|
||||||
|
@var{compute}
|
||||||
|
Return a new extension for services of type @var{target-type}.
|
||||||
|
@var{compute} must be a one-argument procedure: @code{fold-services}
|
||||||
|
calls it, passing it the value associated with the service that provides
|
||||||
|
the extension; it must return a valid value for the target service.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} service-extension? @var{obj}
|
||||||
|
Return true if @var{obj} is a service extension.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
At the core of the service abstraction lies the @code{fold-services}
|
||||||
|
procedure, which is responsible for ``compiling'' a list of services
|
||||||
|
down to a single boot script. In essence, it propagates service
|
||||||
|
extensions down the service graph, updating each node parameters on the
|
||||||
|
way, until it reaches the root node.
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} fold-services @var{services} @
|
||||||
|
[#:target-type @var{boot-service-type}]
|
||||||
|
Fold @var{services} by propagating their extensions down to the root of
|
||||||
|
type @var{target-type}; return the root service adjusted accordingly.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
Lastly, the @code{(gnu services)} module also defines several essential
|
||||||
|
service types, some of which are listed below.
|
||||||
|
|
||||||
|
@defvr {Scheme Variable} boot-service-type
|
||||||
|
The type of the ``boot service'', which is the root of the service
|
||||||
|
graph.
|
||||||
|
@end defvr
|
||||||
|
|
||||||
|
@defvr {Scheme Variable} etc-service-type
|
||||||
|
The type of the @file{/etc} service. This service can be extended by
|
||||||
|
passing it name/file tuples such as:
|
||||||
|
|
||||||
|
@example
|
||||||
|
(list `("issue" ,(plain-file "issue" "Welcome!\n")))
|
||||||
|
@end example
|
||||||
|
|
||||||
|
In this example, the effect would be to add an @file{/etc/issue} file
|
||||||
|
pointing to the given file.
|
||||||
|
@end defvr
|
||||||
|
|
||||||
|
@defvr {Scheme Variable} setuid-program-service-type
|
||||||
|
Type for the ``setuid-program service''. This service collects lists of
|
||||||
|
executable file names, passed as gexps, and adds them to the set of
|
||||||
|
setuid-root programs on the system (@pxref{Setuid Programs}).
|
||||||
|
@end defvr
|
||||||
|
|
||||||
|
|
||||||
|
@node dmd Services
|
||||||
|
@subsubsection dmd Services
|
||||||
|
|
||||||
|
@cindex PID 1
|
||||||
|
@cindex init system
|
||||||
|
The @code{(gnu services dmd)} provides a way to define services managed
|
||||||
|
by GNU@tie{}dmd, which is GuixSD initialization system---the first
|
||||||
|
process that is started when the system boots, aka. PID@tie{}1
|
||||||
|
(@pxref{Introduction,,, dmd, GNU dmd Manual}). The
|
||||||
|
@var{%dmd-root-service} represents PID@tie{}1, of type
|
||||||
|
@var{dmd-root-service-type}; it can be extended by passing it lists of
|
||||||
|
@code{<dmd-service>} objects.
|
||||||
|
|
||||||
|
@deftp {Data Type} dmd-service
|
||||||
|
The data type representing a service managed by dmd.
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{provision}
|
||||||
|
This is a list of symbols denoting what the service provides.
|
||||||
|
|
||||||
|
These are the names that may be passed to @command{deco start},
|
||||||
|
@command{deco status}, and similar commands (@pxref{Invoking deco,,,
|
||||||
|
dmd, GNU dmd Manual}). @xref{Slots of services, the @code{provides}
|
||||||
|
slot,, dmd, GNU dmd Manual}, for details.
|
||||||
|
|
||||||
|
@item @code{requirements} (default: @code{'()})
|
||||||
|
List of symbols denoting the dmd services this one depends on.
|
||||||
|
|
||||||
|
@item @code{respawn?} (default: @code{#t})
|
||||||
|
Whether to restart the service when it stops, for instance when the
|
||||||
|
underlying process dies.
|
||||||
|
|
||||||
|
@item @code{start}
|
||||||
|
@itemx @code{stop} (default: @code{#~(const #f)})
|
||||||
The @code{start} and @code{stop} fields refer to dmd's facilities to
|
The @code{start} and @code{stop} fields refer to dmd's facilities to
|
||||||
start and stop processes (@pxref{Service De- and Constructors,,, dmd,
|
start and stop processes (@pxref{Service De- and Constructors,,, dmd,
|
||||||
GNU dmd Manual}). The @code{provision} field specifies the name under
|
GNU dmd Manual}). They are given as G-expressions that get expanded in
|
||||||
which this service is known to dmd, and @code{documentation} specifies
|
the dmd configuration file (@pxref{G-Expressions}).
|
||||||
on-line documentation. Thus, the commands @command{deco start ncsd},
|
|
||||||
@command{deco stop nscd}, and @command{deco doc nscd} will do what you
|
@item @code{documentation}
|
||||||
would expect (@pxref{Invoking deco,,, dmd, GNU dmd Manual}).
|
A documentation string, as shown when running:
|
||||||
|
|
||||||
|
@example
|
||||||
|
deco doc @var{service-name}
|
||||||
|
@end example
|
||||||
|
|
||||||
|
where @var{service-name} is one of the symbols in @var{provision}
|
||||||
|
(@pxref{Invoking deco,,, dmd, GNU dmd Manual}).
|
||||||
|
@end table
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@defvr {Scheme Variable} dmd-root-service-type
|
||||||
|
The service type for the dmd ``root service''---i.e., PID@tie{}1.
|
||||||
|
|
||||||
|
This is the service type that extensions target when they want to create
|
||||||
|
dmd services (@pxref{Service Types and Services}, for an example). Each
|
||||||
|
extension must pass a list of @code{<dmd-service>}.
|
||||||
|
@end defvr
|
||||||
|
|
||||||
|
@defvr {Scheme Variable} %dmd-root-service
|
||||||
|
This service represents PID@tie{}1.
|
||||||
|
@end defvr
|
||||||
|
|
||||||
|
|
||||||
@node Installing Debugging Files
|
@node Installing Debugging Files
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
digraph "Service Type Dependencies" {
|
||||||
|
dmd [shape = box, fontname = Helvetica];
|
||||||
|
pam [shape = box, fontname = Helvetica];
|
||||||
|
etc [shape = box, fontname = Helvetica];
|
||||||
|
accounts [shape = box, fontname = Helvetica];
|
||||||
|
activation [shape = box, fontname = Helvetica];
|
||||||
|
boot [shape = house, fontname = Helvetica];
|
||||||
|
lshd -> dmd;
|
||||||
|
lshd -> pam;
|
||||||
|
udev -> dmd;
|
||||||
|
nscd -> dmd [label = "extends"];
|
||||||
|
"nss-mdns" -> nscd;
|
||||||
|
"kvm-rules" -> udev;
|
||||||
|
colord -> udev;
|
||||||
|
dbus -> dmd;
|
||||||
|
colord -> dbus;
|
||||||
|
upower -> udev;
|
||||||
|
upower -> dbus;
|
||||||
|
polkit -> dbus;
|
||||||
|
polkit -> pam;
|
||||||
|
elogind -> dbus;
|
||||||
|
elogind -> udev;
|
||||||
|
elogind -> polkit [label = "extends"];
|
||||||
|
dmd -> boot;
|
||||||
|
colord -> accounts;
|
||||||
|
accounts -> activation;
|
||||||
|
accounts -> etc;
|
||||||
|
etc -> activation;
|
||||||
|
activation -> boot;
|
||||||
|
pam -> etc;
|
||||||
|
elogind -> pam;
|
||||||
|
guix -> dmd;
|
||||||
|
guix -> activation;
|
||||||
|
guix -> accounts;
|
||||||
|
}
|
|
@ -348,6 +348,7 @@ GNU_SYSTEM_MODULES = \
|
||||||
gnu/services/avahi.scm \
|
gnu/services/avahi.scm \
|
||||||
gnu/services/base.scm \
|
gnu/services/base.scm \
|
||||||
gnu/services/databases.scm \
|
gnu/services/databases.scm \
|
||||||
|
gnu/services/dbus.scm \
|
||||||
gnu/services/desktop.scm \
|
gnu/services/desktop.scm \
|
||||||
gnu/services/dmd.scm \
|
gnu/services/dmd.scm \
|
||||||
gnu/services/lirc.scm \
|
gnu/services/lirc.scm \
|
||||||
|
|
455
gnu/services.scm
455
gnu/services.scm
|
@ -1,5 +1,5 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -18,49 +18,428 @@
|
||||||
|
|
||||||
(define-module (gnu services)
|
(define-module (gnu services)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (guix monads)
|
||||||
|
#:use-module (guix store)
|
||||||
#:use-module (guix records)
|
#:use-module (guix records)
|
||||||
#:export (service?
|
#:use-module (guix sets)
|
||||||
service
|
#:use-module (guix ui)
|
||||||
service-documentation
|
#:use-module (gnu packages base)
|
||||||
service-provision
|
#:use-module (gnu packages bash)
|
||||||
service-requirement
|
#:use-module (srfi srfi-1)
|
||||||
service-respawn?
|
#:use-module (srfi srfi-9)
|
||||||
service-start
|
#:use-module (srfi srfi-9 gnu)
|
||||||
service-stop
|
#:use-module (srfi srfi-26)
|
||||||
service-auto-start?
|
#:use-module (srfi srfi-34)
|
||||||
service-activate
|
#:use-module (srfi srfi-35)
|
||||||
service-user-accounts
|
#:use-module (ice-9 vlist)
|
||||||
service-user-groups
|
#:use-module (ice-9 match)
|
||||||
service-pam-services))
|
#:export (service-extension
|
||||||
|
service-extension?
|
||||||
|
|
||||||
;;; Commentary:
|
service-type
|
||||||
|
service-type?
|
||||||
|
|
||||||
|
service
|
||||||
|
service?
|
||||||
|
service-kind
|
||||||
|
service-parameters
|
||||||
|
|
||||||
|
fold-services
|
||||||
|
|
||||||
|
service-error?
|
||||||
|
missing-target-service-error?
|
||||||
|
missing-target-service-error-service
|
||||||
|
missing-target-service-error-target-type
|
||||||
|
ambiguous-target-service-error?
|
||||||
|
ambiguous-target-service-error-service
|
||||||
|
ambiguous-target-service-error-target-type
|
||||||
|
|
||||||
|
boot-service-type
|
||||||
|
activation-service-type
|
||||||
|
activation-service->script
|
||||||
|
etc-service-type
|
||||||
|
etc-directory
|
||||||
|
setuid-program-service-type
|
||||||
|
firmware-service-type
|
||||||
|
|
||||||
|
%boot-service
|
||||||
|
%activation-service
|
||||||
|
etc-service
|
||||||
|
|
||||||
|
file-union)) ;XXX: for lack of a better place
|
||||||
|
|
||||||
|
;;; Comment:
|
||||||
;;;
|
;;;
|
||||||
;;; System services as cajoled by dmd.
|
;;; This module defines a broad notion of "service types" and "services."
|
||||||
|
;;;
|
||||||
|
;;; A service type describe how its instances extend instances of other
|
||||||
|
;;; service types. For instance, some services extend the instance of
|
||||||
|
;;; ACCOUNT-SERVICE-TYPE by providing it with accounts and groups to create;
|
||||||
|
;;; others extend DMD-ROOT-SERVICE-TYPE by passing it instances of
|
||||||
|
;;; <dmd-service>.
|
||||||
|
;;;
|
||||||
|
;;; When applicable, the service type defines how it can itself be extended,
|
||||||
|
;;; by providing one procedure to compose extensions, and one procedure to
|
||||||
|
;;; extend itself.
|
||||||
|
;;;
|
||||||
|
;;; A notable service type is BOOT-SERVICE-TYPE, which has a single instance,
|
||||||
|
;;; %BOOT-SERVICE. %BOOT-SERVICE constitutes the root of the service DAG. It
|
||||||
|
;;; produces the boot script that the initrd loads.
|
||||||
|
;;;
|
||||||
|
;;; The 'fold-services' procedure can be passed a list of procedures, which it
|
||||||
|
;;; "folds" by propagating extensions down the graph; it returns the root
|
||||||
|
;;; service after the applying all its extensions.
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(define-record-type* <service>
|
(define-record-type <service-extension>
|
||||||
service make-service
|
(service-extension target compute)
|
||||||
|
service-extension?
|
||||||
|
(target service-extension-target) ;<service-type>
|
||||||
|
(compute service-extension-compute)) ;params -> params
|
||||||
|
|
||||||
|
(define-record-type* <service-type> service-type make-service-type
|
||||||
|
service-type?
|
||||||
|
(name service-type-name) ;symbol (for debugging)
|
||||||
|
|
||||||
|
;; Things extended by services of this type.
|
||||||
|
(extensions service-type-extensions) ;list of <service-extensions>
|
||||||
|
|
||||||
|
;; Given a list of extensions, "compose" them.
|
||||||
|
(compose service-type-compose ;list of Any -> Any
|
||||||
|
(default #f))
|
||||||
|
|
||||||
|
;; Extend the services' own parameters with the extension composition.
|
||||||
|
(extend service-type-extend ;list of Any -> parameters
|
||||||
|
(default #f)))
|
||||||
|
|
||||||
|
(define (write-service-type type port)
|
||||||
|
(format port "#<service-type ~a ~a>"
|
||||||
|
(service-type-name type)
|
||||||
|
(number->string (object-address type) 16)))
|
||||||
|
|
||||||
|
(set-record-type-printer! <service-type> write-service-type)
|
||||||
|
|
||||||
|
;; Services of a given type.
|
||||||
|
(define-record-type <service>
|
||||||
|
(service type parameters)
|
||||||
service?
|
service?
|
||||||
(documentation service-documentation ; string
|
(type service-kind)
|
||||||
(default "[No documentation.]"))
|
(parameters service-parameters))
|
||||||
(provision service-provision) ; list of symbols
|
|
||||||
(requirement service-requirement ; list of symbols
|
|
||||||
(default '()))
|
|
||||||
(respawn? service-respawn? ; Boolean
|
|
||||||
(default #t))
|
;;;
|
||||||
(start service-start) ; g-expression (procedure)
|
;;; Core services.
|
||||||
(stop service-stop ; g-expression (procedure)
|
;;;
|
||||||
(default #~(const #f)))
|
|
||||||
(auto-start? service-auto-start? ; Boolean
|
(define (compute-boot-script mexps)
|
||||||
(default #t))
|
(mlet %store-monad ((gexps (sequence %store-monad mexps)))
|
||||||
(user-accounts service-user-accounts ; list of <user-account>
|
(gexp->file "boot"
|
||||||
(default '()))
|
#~(begin
|
||||||
(user-groups service-user-groups ; list of <user-groups>
|
(use-modules (guix build utils))
|
||||||
(default '()))
|
|
||||||
(pam-services service-pam-services ; list of <pam-service>
|
;; Clean out /tmp and /var/run.
|
||||||
(default '()))
|
;;
|
||||||
(activate service-activate ; gexp
|
;; XXX This needs to happen before service activations, so
|
||||||
(default #f)))
|
;; it has to be here, but this also implicitly assumes
|
||||||
|
;; that /tmp and /var/run are on the root partition.
|
||||||
|
(false-if-exception (delete-file-recursively "/tmp"))
|
||||||
|
(false-if-exception (delete-file-recursively "/var/run"))
|
||||||
|
(false-if-exception (mkdir "/tmp"))
|
||||||
|
(false-if-exception (chmod "/tmp" #o1777))
|
||||||
|
(false-if-exception (mkdir "/var/run"))
|
||||||
|
(false-if-exception (chmod "/var/run" #o755))
|
||||||
|
|
||||||
|
;; Activate the system and spawn dmd.
|
||||||
|
#$@gexps))))
|
||||||
|
|
||||||
|
(define (second-argument a b) b)
|
||||||
|
|
||||||
|
(define boot-service-type
|
||||||
|
;; The service of this type is extended by being passed gexps as monadic
|
||||||
|
;; values. It aggregates them in a single script, as a monadic value, which
|
||||||
|
;; becomes its 'parameters'. It is the only service that extends nothing.
|
||||||
|
(service-type (name 'boot)
|
||||||
|
(extensions '())
|
||||||
|
(compose compute-boot-script)
|
||||||
|
(extend second-argument)))
|
||||||
|
|
||||||
|
(define %boot-service
|
||||||
|
;; This is the ultimate service, the root of the service DAG.
|
||||||
|
(service boot-service-type #t))
|
||||||
|
|
||||||
|
(define* (file-union name files) ;FIXME: Factorize.
|
||||||
|
"Return a <computed-file> that builds a directory containing all of FILES.
|
||||||
|
Each item in FILES must be a list where the first element is the file name to
|
||||||
|
use in the new directory, and the second element is a gexp denoting the target
|
||||||
|
file."
|
||||||
|
(computed-file name
|
||||||
|
#~(begin
|
||||||
|
(mkdir #$output)
|
||||||
|
(chdir #$output)
|
||||||
|
#$@(map (match-lambda
|
||||||
|
((target source)
|
||||||
|
#~(symlink #$source #$target)))
|
||||||
|
files))))
|
||||||
|
|
||||||
|
(define (directory-union name things)
|
||||||
|
"Return a directory that is the union of THINGS."
|
||||||
|
(match things
|
||||||
|
((one)
|
||||||
|
;; Only one thing; return it.
|
||||||
|
one)
|
||||||
|
(_
|
||||||
|
(computed-file name
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build union))
|
||||||
|
(union-build #$output '#$things))
|
||||||
|
#:modules '((guix build union))))))
|
||||||
|
|
||||||
|
(define (modprobe-wrapper)
|
||||||
|
"Return a wrapper for the 'modprobe' command that knows where modules live.
|
||||||
|
|
||||||
|
This wrapper is typically invoked by the Linux kernel ('call_modprobe', in
|
||||||
|
kernel/kmod.c), a situation where the 'LINUX_MODULE_DIRECTORY' environment
|
||||||
|
variable is not set---hence the need for this wrapper."
|
||||||
|
(let ((modprobe "/run/current-system/profile/bin/modprobe"))
|
||||||
|
(gexp->script "modprobe"
|
||||||
|
#~(begin
|
||||||
|
(setenv "LINUX_MODULE_DIRECTORY"
|
||||||
|
"/run/booted-system/kernel/lib/modules")
|
||||||
|
(apply execl #$modprobe
|
||||||
|
(cons #$modprobe (cdr (command-line))))))))
|
||||||
|
|
||||||
|
(define* (activation-service->script service)
|
||||||
|
"Return as a monadic value the activation script for SERVICE, a service of
|
||||||
|
ACTIVATION-SCRIPT-TYPE."
|
||||||
|
(activation-script (service-parameters service)))
|
||||||
|
|
||||||
|
(define (activation-script gexps)
|
||||||
|
"Return the system's activation script, which evaluates GEXPS."
|
||||||
|
(define %modules
|
||||||
|
'((gnu build activation)
|
||||||
|
(gnu build linux-boot)
|
||||||
|
(gnu build linux-modules)
|
||||||
|
(gnu build file-systems)
|
||||||
|
(guix build utils)
|
||||||
|
(guix build syscalls)
|
||||||
|
(guix elf)))
|
||||||
|
|
||||||
|
(define (service-activations)
|
||||||
|
;; Return the activation scripts for SERVICES.
|
||||||
|
(mapm %store-monad
|
||||||
|
(cut gexp->file "activate-service" <>)
|
||||||
|
gexps))
|
||||||
|
|
||||||
|
(mlet* %store-monad ((actions (service-activations))
|
||||||
|
(modules (imported-modules %modules))
|
||||||
|
(compiled (compiled-modules %modules))
|
||||||
|
(modprobe (modprobe-wrapper)))
|
||||||
|
(gexp->file "activate"
|
||||||
|
#~(begin
|
||||||
|
(eval-when (expand load eval)
|
||||||
|
;; Make sure 'use-modules' below succeeds.
|
||||||
|
(set! %load-path (cons #$modules %load-path))
|
||||||
|
(set! %load-compiled-path
|
||||||
|
(cons #$compiled %load-compiled-path)))
|
||||||
|
|
||||||
|
(use-modules (gnu build activation))
|
||||||
|
|
||||||
|
;; Make sure /bin/sh is valid and current.
|
||||||
|
(activate-/bin/sh
|
||||||
|
(string-append #$(canonical-package bash) "/bin/sh"))
|
||||||
|
|
||||||
|
;; Tell the kernel to use our 'modprobe' command.
|
||||||
|
(activate-modprobe #$modprobe)
|
||||||
|
|
||||||
|
;; Let users debug their own processes!
|
||||||
|
(activate-ptrace-attach)
|
||||||
|
|
||||||
|
;; Run the services' activation snippets.
|
||||||
|
;; TODO: Use 'load-compiled'.
|
||||||
|
(for-each primitive-load '#$actions)
|
||||||
|
|
||||||
|
;; Set up /run/current-system.
|
||||||
|
(activate-current-system)))))
|
||||||
|
|
||||||
|
(define (gexps->activation-gexp gexps)
|
||||||
|
"Return a gexp that runs the activation script containing GEXPS."
|
||||||
|
(mlet %store-monad ((script (activation-script gexps)))
|
||||||
|
(return #~(primitive-load #$script))))
|
||||||
|
|
||||||
|
(define activation-service-type
|
||||||
|
(service-type (name 'activate)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension boot-service-type
|
||||||
|
gexps->activation-gexp)))
|
||||||
|
(compose append)
|
||||||
|
(extend second-argument)))
|
||||||
|
|
||||||
|
(define %activation-service
|
||||||
|
;; The activation service produces the activation script from the gexps it
|
||||||
|
;; receives.
|
||||||
|
(service activation-service-type #t))
|
||||||
|
|
||||||
|
(define (etc-directory service)
|
||||||
|
"Return the directory for SERVICE, a service of type ETC-SERVICE-TYPE."
|
||||||
|
(files->etc-directory (service-parameters service)))
|
||||||
|
|
||||||
|
(define (files->etc-directory files)
|
||||||
|
(file-union "etc" files))
|
||||||
|
|
||||||
|
(define etc-service-type
|
||||||
|
(service-type (name 'etc)
|
||||||
|
(extensions
|
||||||
|
(list
|
||||||
|
(service-extension activation-service-type
|
||||||
|
(lambda (files)
|
||||||
|
(let ((etc
|
||||||
|
(files->etc-directory files)))
|
||||||
|
#~(activate-etc #$etc))))))
|
||||||
|
(compose concatenate)
|
||||||
|
(extend append)))
|
||||||
|
|
||||||
|
(define (etc-service files)
|
||||||
|
"Return a new service of ETC-SERVICE-TYPE that populates /etc with FILES.
|
||||||
|
FILES must be a list of name/file-like object pairs."
|
||||||
|
(service etc-service-type files))
|
||||||
|
|
||||||
|
(define setuid-program-service-type
|
||||||
|
(service-type (name 'setuid-program)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension activation-service-type
|
||||||
|
(lambda (programs)
|
||||||
|
#~(activate-setuid-programs
|
||||||
|
(list #$@programs))))))
|
||||||
|
(compose concatenate)
|
||||||
|
(extend append)))
|
||||||
|
|
||||||
|
(define (firmware->activation-gexp firmware)
|
||||||
|
"Return a gexp to make the packages listed in FIRMWARE loadable by the
|
||||||
|
kernel."
|
||||||
|
(let ((directory (directory-union "firmware" firmware)))
|
||||||
|
;; Tell the kernel where firmware is.
|
||||||
|
#~(activate-firmware (string-append #$directory "/lib/firmware"))))
|
||||||
|
|
||||||
|
(define firmware-service-type
|
||||||
|
;; The service that collects firmware.
|
||||||
|
(service-type (name 'firmware)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension activation-service-type
|
||||||
|
firmware->activation-gexp)))
|
||||||
|
(compose concatenate)
|
||||||
|
(extend append)))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Service folding.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define-condition-type &service-error &error
|
||||||
|
service-error?)
|
||||||
|
|
||||||
|
(define-condition-type &missing-target-service-error &service-error
|
||||||
|
missing-target-service-error?
|
||||||
|
(service missing-target-service-error-service)
|
||||||
|
(target-type missing-target-service-error-target-type))
|
||||||
|
|
||||||
|
(define-condition-type &ambiguous-target-service-error &service-error
|
||||||
|
ambiguous-target-service-error?
|
||||||
|
(service ambiguous-target-service-error-service)
|
||||||
|
(target-type ambiguous-target-service-error-target-type))
|
||||||
|
|
||||||
|
(define (service-back-edges services)
|
||||||
|
"Return a procedure that, when passed a <service>, returns the list of
|
||||||
|
<service> objects that depend on it."
|
||||||
|
(define (add-edges service edges)
|
||||||
|
(define (add-edge extension edges)
|
||||||
|
(let ((target-type (service-extension-target extension)))
|
||||||
|
(match (filter (lambda (service)
|
||||||
|
(eq? (service-kind service) target-type))
|
||||||
|
services)
|
||||||
|
((target)
|
||||||
|
(vhash-consq target service edges))
|
||||||
|
(()
|
||||||
|
(raise
|
||||||
|
(condition (&missing-target-service-error
|
||||||
|
(service service)
|
||||||
|
(target-type target-type))
|
||||||
|
(&message
|
||||||
|
(message
|
||||||
|
(format #f (_ "no target of type '~a' for service ~s")
|
||||||
|
(service-type-name target-type)
|
||||||
|
service))))))
|
||||||
|
(x
|
||||||
|
(raise
|
||||||
|
(condition (&ambiguous-target-service-error
|
||||||
|
(service service)
|
||||||
|
(target-type target-type))
|
||||||
|
(&message
|
||||||
|
(message
|
||||||
|
(format #f
|
||||||
|
(_ "more than one target service of type '~a'")
|
||||||
|
(service-type-name target-type))))))))))
|
||||||
|
|
||||||
|
(fold add-edge edges (service-type-extensions (service-kind service))))
|
||||||
|
|
||||||
|
(let ((edges (fold add-edges vlist-null services)))
|
||||||
|
(lambda (node)
|
||||||
|
(reverse (vhash-foldq* cons '() node edges)))))
|
||||||
|
|
||||||
|
(define* (fold-services services #:key (target-type boot-service-type))
|
||||||
|
"Fold SERVICES by propagating their extensions down to the root of type
|
||||||
|
TARGET-TYPE; return the root service adjusted accordingly."
|
||||||
|
(define dependents
|
||||||
|
(service-back-edges services))
|
||||||
|
|
||||||
|
(define (matching-extension target)
|
||||||
|
(let ((target (service-kind target)))
|
||||||
|
(match-lambda
|
||||||
|
(($ <service-extension> type)
|
||||||
|
(eq? type target)))))
|
||||||
|
|
||||||
|
(define (apply-extension target)
|
||||||
|
(lambda (service)
|
||||||
|
(match (find (matching-extension target)
|
||||||
|
(service-type-extensions (service-kind service)))
|
||||||
|
(($ <service-extension> _ compute)
|
||||||
|
(compute (service-parameters service))))))
|
||||||
|
|
||||||
|
(match (filter (lambda (service)
|
||||||
|
(eq? (service-kind service) target-type))
|
||||||
|
services)
|
||||||
|
((sink)
|
||||||
|
(let loop ((sink sink))
|
||||||
|
(let* ((dependents (map loop (dependents sink)))
|
||||||
|
(extensions (map (apply-extension sink) dependents))
|
||||||
|
(extend (service-type-extend (service-kind sink)))
|
||||||
|
(compose (service-type-compose (service-kind sink)))
|
||||||
|
(params (service-parameters sink)))
|
||||||
|
;; We distinguish COMPOSE and EXTEND because PARAMS typically has a
|
||||||
|
;; different type than the elements of EXTENSIONS.
|
||||||
|
(if extend
|
||||||
|
(service (service-kind sink)
|
||||||
|
(extend params (compose extensions)))
|
||||||
|
sink))))
|
||||||
|
(()
|
||||||
|
(raise
|
||||||
|
(condition (&missing-target-service-error
|
||||||
|
(service #f)
|
||||||
|
(target-type target-type))
|
||||||
|
(&message
|
||||||
|
(message (format #f (_ "service of type '~a' not found")
|
||||||
|
(service-type-name target-type)))))))
|
||||||
|
(x
|
||||||
|
(raise
|
||||||
|
(condition (&ambiguous-target-service-error
|
||||||
|
(service #f)
|
||||||
|
(target-type target-type))
|
||||||
|
(&message
|
||||||
|
(message
|
||||||
|
(format #f
|
||||||
|
(_ "more than one target service of type '~a'")
|
||||||
|
(service-type-name target-type)))))))))
|
||||||
|
|
||||||
;;; services.scm ends here.
|
;;; services.scm ends here.
|
||||||
|
|
|
@ -18,10 +18,13 @@
|
||||||
|
|
||||||
(define-module (gnu services avahi)
|
(define-module (gnu services avahi)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services base)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
|
#:use-module (gnu services dbus)
|
||||||
#:use-module (gnu system shadow)
|
#:use-module (gnu system shadow)
|
||||||
#:use-module (gnu packages avahi)
|
#:use-module (gnu packages avahi)
|
||||||
#:use-module (gnu packages admin)
|
#:use-module (gnu packages admin)
|
||||||
#:use-module (guix store)
|
#:use-module (guix records)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
#:export (avahi-service))
|
#:export (avahi-service))
|
||||||
|
|
||||||
|
@ -32,12 +35,27 @@
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(define* (configuration-file #:key host-name publish?
|
;; TODO: Export.
|
||||||
ipv4? ipv6? wide-area? domains-to-browse)
|
(define-record-type* <avahi-configuration>
|
||||||
"Return an avahi-daemon configuration file."
|
avahi-configuration make-avahi-configuration
|
||||||
|
avahi-configuration?
|
||||||
|
(avahi avahi-configuration-avahi ;<package>
|
||||||
|
(default avahi))
|
||||||
|
(host-name avahi-configuration-host-name) ;string
|
||||||
|
(publish? avahi-configuration-publish?) ;Boolean
|
||||||
|
(ipv4? avahi-configuration-ipv4?) ;Boolean
|
||||||
|
(ipv6? avahi-configuration-ipv6?) ;Boolean
|
||||||
|
(wide-area? avahi-configuration-wide-area?) ;Boolean
|
||||||
|
(domains-to-browse avahi-configuration-domains-to-browse)) ;list of strings
|
||||||
|
|
||||||
|
(define* (configuration-file config)
|
||||||
|
"Return an avahi-daemon configuration file based on CONFIG, an
|
||||||
|
<avahi-configuration>."
|
||||||
(define (bool value)
|
(define (bool value)
|
||||||
(if value "yes\n" "no\n"))
|
(if value "yes\n" "no\n"))
|
||||||
|
|
||||||
|
(define host-name (avahi-configuration-host-name config))
|
||||||
|
|
||||||
(plain-file "avahi-daemon.conf"
|
(plain-file "avahi-daemon.conf"
|
||||||
(string-append
|
(string-append
|
||||||
"[server]\n"
|
"[server]\n"
|
||||||
|
@ -45,14 +63,63 @@
|
||||||
(string-append "host-name=" host-name "\n")
|
(string-append "host-name=" host-name "\n")
|
||||||
"")
|
"")
|
||||||
|
|
||||||
"browse-domains=" (string-join domains-to-browse)
|
"browse-domains=" (string-join
|
||||||
|
(avahi-configuration-domains-to-browse
|
||||||
|
config))
|
||||||
"\n"
|
"\n"
|
||||||
"use-ipv4=" (bool ipv4?)
|
"use-ipv4=" (bool (avahi-configuration-ipv4? config))
|
||||||
"use-ipv6=" (bool ipv6?)
|
"use-ipv6=" (bool (avahi-configuration-ipv6? config))
|
||||||
"[wide-area]\n"
|
"[wide-area]\n"
|
||||||
"enable-wide-area=" (bool wide-area?)
|
"enable-wide-area=" (bool (avahi-configuration-wide-area? config))
|
||||||
"[publish]\n"
|
"[publish]\n"
|
||||||
"disable-publishing=" (bool (not publish?)))))
|
"disable-publishing="
|
||||||
|
(bool (not (avahi-configuration-publish? config))))))
|
||||||
|
|
||||||
|
(define %avahi-accounts
|
||||||
|
;; Account and group for the Avahi daemon.
|
||||||
|
(list (user-group (name "avahi") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "avahi")
|
||||||
|
(group "avahi")
|
||||||
|
(system? #t)
|
||||||
|
(comment "Avahi daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define %avahi-activation
|
||||||
|
;; Activation gexp.
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
(mkdir-p "/var/run/avahi-daemon")))
|
||||||
|
|
||||||
|
(define (avahi-dmd-service config)
|
||||||
|
"Return a list of <dmd-service> for CONFIG."
|
||||||
|
(let ((config (configuration-file config))
|
||||||
|
(avahi (avahi-configuration-avahi config)))
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the Avahi mDNS/DNS-SD responder.")
|
||||||
|
(provision '(avahi-daemon))
|
||||||
|
(requirement '(dbus-system networking))
|
||||||
|
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$avahi "/sbin/avahi-daemon")
|
||||||
|
"--syslog" "-f" #$config)))
|
||||||
|
(stop #~(make-kill-destructor))))))
|
||||||
|
|
||||||
|
(define avahi-service-type
|
||||||
|
(service-type (name 'avahi)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
avahi-dmd-service)
|
||||||
|
(service-extension dbus-root-service-type
|
||||||
|
(compose list
|
||||||
|
avahi-configuration-avahi))
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %avahi-accounts))
|
||||||
|
(service-extension activation-service-type
|
||||||
|
(const %avahi-activation))
|
||||||
|
(service-extension nscd-service-type
|
||||||
|
(const (list nss-mdns)))))))
|
||||||
|
|
||||||
(define* (avahi-service #:key (avahi avahi)
|
(define* (avahi-service #:key (avahi avahi)
|
||||||
host-name
|
host-name
|
||||||
|
@ -75,36 +142,11 @@ When @var{wide-area?} is true, DNS-SD over unicast DNS is enabled.
|
||||||
|
|
||||||
Boolean values @var{ipv4?} and @var{ipv6?} determine whether to use IPv4/IPv6
|
Boolean values @var{ipv4?} and @var{ipv6?} determine whether to use IPv4/IPv6
|
||||||
sockets."
|
sockets."
|
||||||
(let ((config (configuration-file #:host-name host-name
|
(service avahi-service-type
|
||||||
#:publish? publish?
|
(avahi-configuration
|
||||||
#:ipv4? ipv4?
|
(avahi avahi) (host-name host-name)
|
||||||
#:ipv6? ipv6?
|
(publish? publish?) (ipv4? ipv4?) (ipv6? ipv6?)
|
||||||
#:wide-area? wide-area?
|
(wide-area? wide-area?)
|
||||||
#:domains-to-browse
|
(domains-to-browse domains-to-browse))))
|
||||||
domains-to-browse)))
|
|
||||||
(service
|
|
||||||
(documentation "Run the Avahi mDNS/DNS-SD responder.")
|
|
||||||
(provision '(avahi-daemon))
|
|
||||||
(requirement '(dbus-system networking))
|
|
||||||
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$avahi "/sbin/avahi-daemon")
|
|
||||||
"--syslog" "-f" #$config)))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(activate #~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
(mkdir-p "/var/run/avahi-daemon")))
|
|
||||||
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "avahi")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "avahi")
|
|
||||||
(group "avahi")
|
|
||||||
(system? #t)
|
|
||||||
(comment "Avahi daemon user")
|
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell
|
|
||||||
#~(string-append #$shadow "/sbin/nologin"))))))))
|
|
||||||
|
|
||||||
;;; avahi.scm ends here
|
;;; avahi.scm ends here
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,12 +19,13 @@
|
||||||
|
|
||||||
(define-module (gnu services databases)
|
(define-module (gnu services databases)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
#:use-module (gnu system shadow)
|
#:use-module (gnu system shadow)
|
||||||
#:use-module (gnu packages admin)
|
#:use-module (gnu packages admin)
|
||||||
#:use-module (gnu packages databases)
|
#:use-module (gnu packages databases)
|
||||||
#:use-module (guix records)
|
#:use-module (guix records)
|
||||||
#:use-module (guix store)
|
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
#:export (postgresql-service))
|
#:export (postgresql-service))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
|
@ -33,6 +34,14 @@
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
(define-record-type* <postgresql-configuration>
|
||||||
|
postgresql-configuration make-postgresql-configuration
|
||||||
|
postgresql-configuration?
|
||||||
|
(postgresql postgresql-configuration-postgresql ;<package>
|
||||||
|
(default postgresql))
|
||||||
|
(config-file postgresql-configuration-file)
|
||||||
|
(data-directory postgresql-configuration-data-directory))
|
||||||
|
|
||||||
(define %default-postgres-hba
|
(define %default-postgres-hba
|
||||||
(plain-file "pg_hba.conf"
|
(plain-file "pg_hba.conf"
|
||||||
"
|
"
|
||||||
|
@ -49,6 +58,77 @@ host all all ::1/128 trust"))
|
||||||
"hba_file = '" %default-postgres-hba "'\n"
|
"hba_file = '" %default-postgres-hba "'\n"
|
||||||
"ident_file = '" %default-postgres-ident "\n"))
|
"ident_file = '" %default-postgres-ident "\n"))
|
||||||
|
|
||||||
|
(define %postgresql-accounts
|
||||||
|
(list (user-group (name "postgres") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "postgres")
|
||||||
|
(group "postgres")
|
||||||
|
(system? #t)
|
||||||
|
(comment "PostgreSQL server user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define postgresql-activation
|
||||||
|
(match-lambda
|
||||||
|
(($ <postgresql-configuration> postgresql config-file data-directory)
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils)
|
||||||
|
(ice-9 match))
|
||||||
|
|
||||||
|
(let ((user (getpwnam "postgres"))
|
||||||
|
(initdb (string-append #$postgresql "/bin/initdb")))
|
||||||
|
;; Create db state directory.
|
||||||
|
(mkdir-p #$data-directory)
|
||||||
|
(chown #$data-directory (passwd:uid user) (passwd:gid user))
|
||||||
|
|
||||||
|
;; Drop privileges and init state directory in a new
|
||||||
|
;; process. Wait for it to finish before proceeding.
|
||||||
|
(match (primitive-fork)
|
||||||
|
(0
|
||||||
|
;; Exit with a non-zero status code if an exception is thrown.
|
||||||
|
(dynamic-wind
|
||||||
|
(const #t)
|
||||||
|
(lambda ()
|
||||||
|
(setgid (passwd:gid user))
|
||||||
|
(setuid (passwd:uid user))
|
||||||
|
(primitive-exit (system* initdb "-D" #$data-directory)))
|
||||||
|
(lambda ()
|
||||||
|
(primitive-exit 1))))
|
||||||
|
(pid (waitpid pid))))))))
|
||||||
|
|
||||||
|
(define postgresql-dmd-service
|
||||||
|
(match-lambda
|
||||||
|
(($ <postgresql-configuration> postgresql config-file data-directory)
|
||||||
|
(let ((start-script
|
||||||
|
;; Wrapper script that switches to the 'postgres' user before
|
||||||
|
;; launching daemon.
|
||||||
|
(program-file "start-postgres"
|
||||||
|
#~(let ((user (getpwnam "postgres"))
|
||||||
|
(postgres (string-append #$postgresql
|
||||||
|
"/bin/postgres")))
|
||||||
|
(setgid (passwd:gid user))
|
||||||
|
(setuid (passwd:uid user))
|
||||||
|
(system* postgres
|
||||||
|
(string-append "--config-file="
|
||||||
|
#$config-file)
|
||||||
|
"-D" #$data-directory)))))
|
||||||
|
(list (dmd-service
|
||||||
|
(provision '(postgres))
|
||||||
|
(documentation "Run the PostgreSQL daemon.")
|
||||||
|
(requirement '(user-processes loopback))
|
||||||
|
(start #~(make-forkexec-constructor #$start-script))
|
||||||
|
(stop #~(make-kill-destructor))))))))
|
||||||
|
|
||||||
|
(define postgresql-service-type
|
||||||
|
(service-type (name 'postgresql)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
postgresql-dmd-service)
|
||||||
|
(service-extension activation-service-type
|
||||||
|
postgresql-activation)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %postgresql-accounts))))))
|
||||||
|
|
||||||
(define* (postgresql-service #:key (postgresql postgresql)
|
(define* (postgresql-service #:key (postgresql postgresql)
|
||||||
(config-file %default-postgres-config)
|
(config-file %default-postgres-config)
|
||||||
(data-directory "/var/lib/postgresql/data"))
|
(data-directory "/var/lib/postgresql/data"))
|
||||||
|
@ -56,60 +136,8 @@ host all all ::1/128 trust"))
|
||||||
|
|
||||||
The PostgreSQL daemon loads its runtime configuration from @var{config-file}
|
The PostgreSQL daemon loads its runtime configuration from @var{config-file}
|
||||||
and stores the database cluster in @var{data-directory}."
|
and stores the database cluster in @var{data-directory}."
|
||||||
;; Wrapper script that switches to the 'postgres' user before launching
|
(service postgresql-service-type
|
||||||
;; daemon.
|
(postgresql-configuration
|
||||||
(define start-script
|
(postgresql postgresql)
|
||||||
(program-file "start-postgres"
|
(config-file config-file)
|
||||||
#~(let ((user (getpwnam "postgres"))
|
(data-directory data-directory))))
|
||||||
(postgres (string-append #$postgresql
|
|
||||||
"/bin/postgres")))
|
|
||||||
(setgid (passwd:gid user))
|
|
||||||
(setuid (passwd:uid user))
|
|
||||||
(system* postgres
|
|
||||||
(string-append "--config-file=" #$config-file)
|
|
||||||
"-D" #$data-directory))))
|
|
||||||
|
|
||||||
(define activate
|
|
||||||
#~(begin
|
|
||||||
(use-modules (guix build utils)
|
|
||||||
(ice-9 match))
|
|
||||||
|
|
||||||
(let ((user (getpwnam "postgres"))
|
|
||||||
(initdb (string-append #$postgresql "/bin/initdb")))
|
|
||||||
;; Create db state directory.
|
|
||||||
(mkdir-p #$data-directory)
|
|
||||||
(chown #$data-directory (passwd:uid user) (passwd:gid user))
|
|
||||||
|
|
||||||
;; Drop privileges and init state directory in a new
|
|
||||||
;; process. Wait for it to finish before proceeding.
|
|
||||||
(match (primitive-fork)
|
|
||||||
(0
|
|
||||||
;; Exit with a non-zero status code if an exception is thrown.
|
|
||||||
(dynamic-wind
|
|
||||||
(const #t)
|
|
||||||
(lambda ()
|
|
||||||
(setgid (passwd:gid user))
|
|
||||||
(setuid (passwd:uid user))
|
|
||||||
(primitive-exit (system* initdb "-D" #$data-directory)))
|
|
||||||
(lambda ()
|
|
||||||
(primitive-exit 1))))
|
|
||||||
(pid (waitpid pid))))))
|
|
||||||
|
|
||||||
(service
|
|
||||||
(provision '(postgres))
|
|
||||||
(documentation "Run the PostgreSQL daemon.")
|
|
||||||
(requirement '(user-processes loopback))
|
|
||||||
(start #~(make-forkexec-constructor #$start-script))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(activate activate)
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "postgres")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "postgres")
|
|
||||||
(group "postgres")
|
|
||||||
(system? #t)
|
|
||||||
(comment "PostgreSQL server user")
|
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell
|
|
||||||
#~(string-append #$shadow "/sbin/nologin")))))))
|
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
|
;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@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 services dbus)
|
||||||
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
|
#:use-module (gnu system shadow)
|
||||||
|
#:use-module (gnu packages glib)
|
||||||
|
#:use-module (gnu packages admin)
|
||||||
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (guix records)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
|
#:export (dbus-root-service-type
|
||||||
|
dbus-service))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; D-Bus.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define-record-type* <dbus-configuration>
|
||||||
|
dbus-configuration make-dbus-configuration
|
||||||
|
dbus-configuration?
|
||||||
|
(dbus dbus-configuration-dbus ;<package>
|
||||||
|
(default dbus))
|
||||||
|
(services dbus-configuration-services ;list of <package>
|
||||||
|
(default '())))
|
||||||
|
|
||||||
|
(define (dbus-configuration-directory dbus services)
|
||||||
|
"Return a configuration directory for @var{dbus} that includes the
|
||||||
|
@code{etc/dbus-1/system.d} directories of each package listed in
|
||||||
|
@var{services}."
|
||||||
|
(define build
|
||||||
|
#~(begin
|
||||||
|
(use-modules (sxml simple)
|
||||||
|
(srfi srfi-1))
|
||||||
|
|
||||||
|
(define (services->sxml services)
|
||||||
|
;; Return the SXML 'includedir' clauses for DIRS.
|
||||||
|
`(busconfig
|
||||||
|
,@(append-map (lambda (dir)
|
||||||
|
`((includedir
|
||||||
|
,(string-append dir "/etc/dbus-1/system.d"))
|
||||||
|
(servicedir ;for '.service' files
|
||||||
|
,(string-append dir "/share/dbus-1/services"))
|
||||||
|
(servicedir ;likewise, for auto-activation
|
||||||
|
,(string-append
|
||||||
|
dir
|
||||||
|
"/share/dbus-1/system-services"))))
|
||||||
|
services)))
|
||||||
|
|
||||||
|
(mkdir #$output)
|
||||||
|
(copy-file (string-append #$dbus "/etc/dbus-1/system.conf")
|
||||||
|
(string-append #$output "/system.conf"))
|
||||||
|
|
||||||
|
;; The default 'system.conf' has an <includedir> clause for
|
||||||
|
;; 'system.d', so create it.
|
||||||
|
(mkdir (string-append #$output "/system.d"))
|
||||||
|
|
||||||
|
;; 'system-local.conf' is automatically included by the default
|
||||||
|
;; 'system.conf', so this is where we stuff our own things.
|
||||||
|
(call-with-output-file (string-append #$output "/system-local.conf")
|
||||||
|
(lambda (port)
|
||||||
|
(sxml->xml (services->sxml (list #$@services))
|
||||||
|
port)))))
|
||||||
|
|
||||||
|
(computed-file "dbus-configuration" build))
|
||||||
|
|
||||||
|
(define %dbus-accounts
|
||||||
|
;; Accounts used by the system bus.
|
||||||
|
(list (user-group (name "messagebus") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "messagebus")
|
||||||
|
(group "messagebus")
|
||||||
|
(system? #t)
|
||||||
|
(comment "D-Bus system bus user")
|
||||||
|
(home-directory "/var/run/dbus")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define (dbus-activation config)
|
||||||
|
"Return an activation gexp for D-Bus using @var{config}."
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
|
||||||
|
(mkdir-p "/var/run/dbus")
|
||||||
|
|
||||||
|
(let ((user (getpwnam "messagebus")))
|
||||||
|
(chown "/var/run/dbus"
|
||||||
|
(passwd:uid user) (passwd:gid user)))
|
||||||
|
|
||||||
|
(unless (file-exists? "/etc/machine-id")
|
||||||
|
(format #t "creating /etc/machine-id...~%")
|
||||||
|
(let ((prog (string-append #$(dbus-configuration-dbus config)
|
||||||
|
"/bin/dbus-uuidgen")))
|
||||||
|
;; XXX: We can't use 'system' because the initrd's
|
||||||
|
;; guile system(3) only works when 'sh' is in $PATH.
|
||||||
|
(let ((pid (primitive-fork)))
|
||||||
|
(if (zero? pid)
|
||||||
|
(call-with-output-file "/etc/machine-id"
|
||||||
|
(lambda (port)
|
||||||
|
(close-fdes 1)
|
||||||
|
(dup2 (port->fdes port) 1)
|
||||||
|
(execl prog)))
|
||||||
|
(waitpid pid)))))))
|
||||||
|
|
||||||
|
(define dbus-dmd-service
|
||||||
|
(match-lambda
|
||||||
|
(($ <dbus-configuration> dbus services)
|
||||||
|
(let ((conf (dbus-configuration-directory dbus services)))
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the D-Bus system daemon.")
|
||||||
|
(provision '(dbus-system))
|
||||||
|
(requirement '(user-processes))
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$dbus "/bin/dbus-daemon")
|
||||||
|
"--nofork"
|
||||||
|
(string-append "--config-file=" #$conf
|
||||||
|
"/system.conf"))))
|
||||||
|
(stop #~(make-kill-destructor))))))))
|
||||||
|
|
||||||
|
(define dbus-root-service-type
|
||||||
|
(service-type (name 'dbus)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
dbus-dmd-service)
|
||||||
|
(service-extension activation-service-type
|
||||||
|
dbus-activation)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %dbus-accounts))))
|
||||||
|
|
||||||
|
;; Extensions consist of lists of packages (representing D-Bus
|
||||||
|
;; services) that we just concatenate.
|
||||||
|
;;
|
||||||
|
;; FIXME: We need 'dbus-daemon-launch-helper' to be
|
||||||
|
;; setuid-root for auto-activation to work.
|
||||||
|
(compose concatenate)
|
||||||
|
|
||||||
|
;; The service's parameters field is extended by augmenting
|
||||||
|
;; its <dbus-configuration> 'services' field.
|
||||||
|
(extend (lambda (config services)
|
||||||
|
(dbus-configuration
|
||||||
|
(inherit config)
|
||||||
|
(services
|
||||||
|
(append (dbus-configuration-services config)
|
||||||
|
services)))))))
|
||||||
|
|
||||||
|
(define* (dbus-service #:key (dbus dbus) (services '()))
|
||||||
|
"Return a service that runs the \"system bus\", using @var{dbus}, with
|
||||||
|
support for @var{services}.
|
||||||
|
|
||||||
|
@uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication
|
||||||
|
facility. Its system bus is used to allow system services to communicate and
|
||||||
|
be notified of system-wide events.
|
||||||
|
|
||||||
|
@var{services} must be a list of packages that provide an
|
||||||
|
@file{etc/dbus-1/system.d} directory containing additional D-Bus configuration
|
||||||
|
and policy files. For example, to allow avahi-daemon to use the system bus,
|
||||||
|
@var{services} must be equal to @code{(list avahi)}."
|
||||||
|
(service dbus-root-service-type
|
||||||
|
(dbus-configuration (dbus dbus)
|
||||||
|
(services services))))
|
||||||
|
|
||||||
|
;;; dbus.scm ends here
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
(define-module (gnu services desktop)
|
(define-module (gnu services desktop)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
#:use-module (gnu services base)
|
#:use-module (gnu services base)
|
||||||
|
#:use-module (gnu services dbus)
|
||||||
#:use-module (gnu services avahi)
|
#:use-module (gnu services avahi)
|
||||||
#:use-module (gnu services xorg)
|
#:use-module (gnu services xorg)
|
||||||
#:use-module (gnu services networking)
|
#:use-module (gnu services networking)
|
||||||
|
@ -31,16 +33,14 @@
|
||||||
#:use-module (gnu packages freedesktop)
|
#:use-module (gnu packages freedesktop)
|
||||||
#:use-module (gnu packages gnome)
|
#:use-module (gnu packages gnome)
|
||||||
#:use-module (gnu packages avahi)
|
#:use-module (gnu packages avahi)
|
||||||
#:use-module (gnu packages wicd)
|
|
||||||
#:use-module (gnu packages polkit)
|
#:use-module (gnu packages polkit)
|
||||||
#:use-module ((gnu packages linux)
|
|
||||||
#:select (lvm2 fuse alsa-utils crda))
|
|
||||||
#:use-module (guix records)
|
#:use-module (guix records)
|
||||||
|
#:use-module (guix packages)
|
||||||
#:use-module (guix store)
|
#:use-module (guix store)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:export (dbus-service
|
#:export (upower-service
|
||||||
upower-service
|
|
||||||
colord-service
|
colord-service
|
||||||
geoclue-application
|
geoclue-application
|
||||||
%standard-geoclue-applications
|
%standard-geoclue-applications
|
||||||
|
@ -64,133 +64,149 @@
|
||||||
(define (bool value)
|
(define (bool value)
|
||||||
(if value "true\n" "false\n"))
|
(if value "true\n" "false\n"))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
|
||||||
;;; D-Bus.
|
|
||||||
;;;
|
|
||||||
|
|
||||||
(define (dbus-configuration-directory dbus services)
|
(define (wrapped-dbus-service service program variable value)
|
||||||
"Return a configuration directory for @var{dbus} that includes the
|
"Return a wrapper for @var{service}, a package containing a D-Bus service,
|
||||||
@code{etc/dbus-1/system.d} directories of each package listed in
|
where @var{program} is wrapped such that environment variable @var{variable}
|
||||||
@var{services}."
|
is set to @var{value} when the bus daemon launches it."
|
||||||
(define build
|
(define wrapper
|
||||||
#~(begin
|
(program-file (string-append (package-name service) "-program-wrapper")
|
||||||
(use-modules (sxml simple)
|
#~(begin
|
||||||
(srfi srfi-1))
|
(setenv #$variable #$value)
|
||||||
|
(apply execl (string-append #$service "/" #$program)
|
||||||
|
(string-append #$service "/" #$program)
|
||||||
|
(cdr (command-line))))))
|
||||||
|
|
||||||
(define (services->sxml services)
|
(computed-file (string-append (package-name service) "-wrapper")
|
||||||
;; Return the SXML 'includedir' clauses for DIRS.
|
#~(begin
|
||||||
`(busconfig
|
(use-modules (guix build utils))
|
||||||
,@(append-map (lambda (dir)
|
|
||||||
`((includedir
|
|
||||||
,(string-append dir "/etc/dbus-1/system.d"))
|
|
||||||
(servicedir ;for '.service' files
|
|
||||||
,(string-append dir "/share/dbus-1/services"))))
|
|
||||||
services)))
|
|
||||||
|
|
||||||
(mkdir #$output)
|
(define service-directory
|
||||||
(copy-file (string-append #$dbus "/etc/dbus-1/system.conf")
|
"/share/dbus-1/system-services")
|
||||||
(string-append #$output "/system.conf"))
|
|
||||||
|
|
||||||
;; The default 'system.conf' has an <includedir> clause for
|
(mkdir-p (dirname (string-append #$output
|
||||||
;; 'system.d', so create it.
|
service-directory)))
|
||||||
(mkdir (string-append #$output "/system.d"))
|
(copy-recursively (string-append #$service
|
||||||
|
service-directory)
|
||||||
|
(string-append #$output
|
||||||
|
service-directory))
|
||||||
|
(symlink (string-append #$service "/etc") ;for etc/dbus-1
|
||||||
|
(string-append #$output "/etc"))
|
||||||
|
|
||||||
;; 'system-local.conf' is automatically included by the default
|
(for-each (lambda (file)
|
||||||
;; 'system.conf', so this is where we stuff our own things.
|
(substitute* file
|
||||||
(call-with-output-file (string-append #$output "/system-local.conf")
|
(("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$"
|
||||||
(lambda (port)
|
_ original-program arguments)
|
||||||
(sxml->xml (services->sxml (list #$@services))
|
(string-append "Exec=" #$wrapper arguments
|
||||||
port)))))
|
"\n"))))
|
||||||
|
(find-files #$output "\\.service$")))
|
||||||
(computed-file "dbus-configuration" build))
|
#:modules '((guix build utils))))
|
||||||
|
|
||||||
(define* (dbus-service services #:key (dbus dbus))
|
|
||||||
"Return a service that runs the \"system bus\", using @var{dbus}, with
|
|
||||||
support for @var{services}.
|
|
||||||
|
|
||||||
@uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication
|
|
||||||
facility. Its system bus is used to allow system services to communicate and
|
|
||||||
be notified of system-wide events.
|
|
||||||
|
|
||||||
@var{services} must be a list of packages that provide an
|
|
||||||
@file{etc/dbus-1/system.d} directory containing additional D-Bus configuration
|
|
||||||
and policy files. For example, to allow avahi-daemon to use the system bus,
|
|
||||||
@var{services} must be equal to @code{(list avahi)}."
|
|
||||||
(let ((conf (dbus-configuration-directory dbus services)))
|
|
||||||
(service
|
|
||||||
(documentation "Run the D-Bus system daemon.")
|
|
||||||
(provision '(dbus-system))
|
|
||||||
(requirement '(user-processes))
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$dbus "/bin/dbus-daemon")
|
|
||||||
"--nofork"
|
|
||||||
(string-append "--config-file=" #$conf "/system.conf"))))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "messagebus")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "messagebus")
|
|
||||||
(group "messagebus")
|
|
||||||
(system? #t)
|
|
||||||
(comment "D-Bus system bus user")
|
|
||||||
(home-directory "/var/run/dbus")
|
|
||||||
(shell
|
|
||||||
#~(string-append #$shadow "/sbin/nologin")))))
|
|
||||||
(activate #~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
|
|
||||||
(mkdir-p "/var/run/dbus")
|
|
||||||
|
|
||||||
(let ((user (getpwnam "messagebus")))
|
|
||||||
(chown "/var/run/dbus"
|
|
||||||
(passwd:uid user) (passwd:gid user)))
|
|
||||||
|
|
||||||
(unless (file-exists? "/etc/machine-id")
|
|
||||||
(format #t "creating /etc/machine-id...~%")
|
|
||||||
(let ((prog (string-append #$dbus "/bin/dbus-uuidgen")))
|
|
||||||
;; XXX: We can't use 'system' because the initrd's
|
|
||||||
;; guile system(3) only works when 'sh' is in $PATH.
|
|
||||||
(let ((pid (primitive-fork)))
|
|
||||||
(if (zero? pid)
|
|
||||||
(call-with-output-file "/etc/machine-id"
|
|
||||||
(lambda (port)
|
|
||||||
(close-fdes 1)
|
|
||||||
(dup2 (port->fdes port) 1)
|
|
||||||
(execl prog)))
|
|
||||||
(waitpid pid))))))))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Upower D-Bus service.
|
;;; Upower D-Bus service.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(define* (upower-configuration-file #:key watts-up-pro? poll-batteries?
|
;; TODO: Export.
|
||||||
ignore-lid? use-percentage-for-policy?
|
(define-record-type* <upower-configuration>
|
||||||
percentage-low percentage-critical
|
upower-configuration make-upower-configuration
|
||||||
percentage-action time-low
|
upower-configuration?
|
||||||
time-critical time-action
|
(upower upower-configuration-upower
|
||||||
critical-power-action)
|
(default upower))
|
||||||
"Return an upower-daemon configuration file."
|
(watts-up-pro? upower-configuration-watts-up-pro?)
|
||||||
(plain-file "UPower.conf"
|
(poll-batteries? upower-configuration-poll-batteries?)
|
||||||
(string-append
|
(ignore-lid? upower-configuration-ignore-lid?)
|
||||||
"[UPower]\n"
|
(use-percentage-for-policy? upower-configuration-use-percentage-for-policy?)
|
||||||
"EnableWattsUpPro=" (bool watts-up-pro?)
|
(percentage-low upower-configuration-percentage-low)
|
||||||
"NoPollBatteries=" (bool (not poll-batteries?))
|
(percentage-critical upower-configuration-percentage-critical)
|
||||||
"IgnoreLid=" (bool ignore-lid?)
|
(percentage-action upower-configuration-percentage-action)
|
||||||
"UsePercentageForPolicy=" (bool use-percentage-for-policy?)
|
(time-low upower-configuration-time-low)
|
||||||
"PercentageLow=" (number->string percentage-low) "\n"
|
(time-critical upower-configuration-time-critical)
|
||||||
"PercentageCritical=" (number->string percentage-critical) "\n"
|
(time-action upower-configuration-time-action)
|
||||||
"PercentageAction=" (number->string percentage-action) "\n"
|
(critical-power-action upower-configuration-critical-power-action))
|
||||||
"TimeLow=" (number->string time-low) "\n"
|
|
||||||
"TimeCritical=" (number->string time-critical) "\n"
|
(define* upower-configuration-file
|
||||||
"TimeAction=" (number->string time-action) "\n"
|
;; Return an upower-daemon configuration file.
|
||||||
"CriticalPowerAction=" (match critical-power-action
|
(match-lambda
|
||||||
('hybrid-sleep "HybridSleep")
|
(($ <upower-configuration> upower
|
||||||
('hibernate "Hibernate")
|
watts-up-pro? poll-batteries? ignore-lid? use-percentage-for-policy?
|
||||||
('power-off "PowerOff"))
|
percentage-low percentage-critical percentage-action time-low
|
||||||
"\n")))
|
time-critical time-action critical-power-action)
|
||||||
|
(plain-file "UPower.conf"
|
||||||
|
(string-append
|
||||||
|
"[UPower]\n"
|
||||||
|
"EnableWattsUpPro=" (bool watts-up-pro?)
|
||||||
|
"NoPollBatteries=" (bool (not poll-batteries?))
|
||||||
|
"IgnoreLid=" (bool ignore-lid?)
|
||||||
|
"UsePercentageForPolicy=" (bool use-percentage-for-policy?)
|
||||||
|
"PercentageLow=" (number->string percentage-low) "\n"
|
||||||
|
"PercentageCritical=" (number->string percentage-critical) "\n"
|
||||||
|
"PercentageAction=" (number->string percentage-action) "\n"
|
||||||
|
"TimeLow=" (number->string time-low) "\n"
|
||||||
|
"TimeCritical=" (number->string time-critical) "\n"
|
||||||
|
"TimeAction=" (number->string time-action) "\n"
|
||||||
|
"CriticalPowerAction=" (match critical-power-action
|
||||||
|
('hybrid-sleep "HybridSleep")
|
||||||
|
('hibernate "Hibernate")
|
||||||
|
('power-off "PowerOff"))
|
||||||
|
"\n")))))
|
||||||
|
|
||||||
|
(define %upower-accounts ;XXX: useful?
|
||||||
|
(list (user-group (name "upower") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "upower")
|
||||||
|
(group "upower")
|
||||||
|
(system? #t)
|
||||||
|
(comment "UPower daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define %upower-activation
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
(mkdir-p "/var/lib/upower")
|
||||||
|
(let ((user (getpwnam "upower")))
|
||||||
|
(chown "/var/lib/upower"
|
||||||
|
(passwd:uid user) (passwd:gid user)))))
|
||||||
|
|
||||||
|
|
||||||
|
(define (upower-dbus-service config)
|
||||||
|
(list (wrapped-dbus-service (upower-configuration-upower config)
|
||||||
|
"libexec/upowerd"
|
||||||
|
"UPOWER_CONF_FILE_NAME"
|
||||||
|
(upower-configuration-file config))))
|
||||||
|
|
||||||
|
(define (upower-dmd-service config)
|
||||||
|
"Return a dmd service for UPower with CONFIG."
|
||||||
|
(let ((upower (upower-configuration-upower config))
|
||||||
|
(config (upower-configuration-file config)))
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the UPower power and battery monitor.")
|
||||||
|
(provision '(upower-daemon))
|
||||||
|
(requirement '(dbus-system udev))
|
||||||
|
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$upower "/libexec/upowerd"))
|
||||||
|
#:environment-variables
|
||||||
|
(list (string-append "UPOWER_CONF_FILE_NAME="
|
||||||
|
#$config))))
|
||||||
|
(stop #~(make-kill-destructor))))))
|
||||||
|
|
||||||
|
(define upower-service-type
|
||||||
|
(service-type (name 'upower)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dbus-root-service-type
|
||||||
|
upower-dbus-service)
|
||||||
|
(service-extension dmd-root-service-type
|
||||||
|
upower-dmd-service)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %upower-accounts))
|
||||||
|
(service-extension activation-service-type
|
||||||
|
(const %upower-activation))
|
||||||
|
(service-extension udev-service-type
|
||||||
|
(compose
|
||||||
|
list
|
||||||
|
upower-configuration-upower))))))
|
||||||
|
|
||||||
(define* (upower-service #:key (upower upower)
|
(define* (upower-service #:key (upower upower)
|
||||||
(watts-up-pro? #f)
|
(watts-up-pro? #f)
|
||||||
|
@ -208,90 +224,97 @@ and policy files. For example, to allow avahi-daemon to use the system bus,
|
||||||
@command{upowerd}}, a system-wide monitor for power consumption and battery
|
@command{upowerd}}, a system-wide monitor for power consumption and battery
|
||||||
levels, with the given configuration settings. It implements the
|
levels, with the given configuration settings. It implements the
|
||||||
@code{org.freedesktop.UPower} D-Bus interface, and is notably used by GNOME."
|
@code{org.freedesktop.UPower} D-Bus interface, and is notably used by GNOME."
|
||||||
(let ((config (upower-configuration-file
|
(let ((config (upower-configuration
|
||||||
#:watts-up-pro? watts-up-pro?
|
(watts-up-pro? watts-up-pro?)
|
||||||
#:poll-batteries? poll-batteries?
|
(poll-batteries? poll-batteries?)
|
||||||
#:ignore-lid? ignore-lid?
|
(ignore-lid? ignore-lid?)
|
||||||
#:use-percentage-for-policy? use-percentage-for-policy?
|
(use-percentage-for-policy? use-percentage-for-policy?)
|
||||||
#:percentage-low percentage-low
|
(percentage-low percentage-low)
|
||||||
#:percentage-critical percentage-critical
|
(percentage-critical percentage-critical)
|
||||||
#:percentage-action percentage-action
|
(percentage-action percentage-action)
|
||||||
#:time-low time-low
|
(time-low time-low)
|
||||||
#:time-critical time-critical
|
(time-critical time-critical)
|
||||||
#:time-action time-action
|
(time-action time-action)
|
||||||
#:critical-power-action critical-power-action)))
|
(critical-power-action critical-power-action))))
|
||||||
(service
|
(service upower-service-type config)))
|
||||||
(documentation "Run the UPower power and battery monitor.")
|
|
||||||
(provision '(upower-daemon))
|
|
||||||
(requirement '(dbus-system udev))
|
|
||||||
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$upower "/libexec/upowerd"))
|
|
||||||
#:environment-variables
|
|
||||||
(list (string-append "UPOWER_CONF_FILE_NAME=" #$config))))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(activate #~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
(mkdir-p "/var/lib/upower")
|
|
||||||
(let ((user (getpwnam "upower")))
|
|
||||||
(chown "/var/lib/upower"
|
|
||||||
(passwd:uid user) (passwd:gid user)))))
|
|
||||||
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "upower")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "upower")
|
|
||||||
(group "upower")
|
|
||||||
(system? #t)
|
|
||||||
(comment "UPower daemon user")
|
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell
|
|
||||||
#~(string-append #$shadow "/sbin/nologin"))))))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Colord D-Bus service.
|
;;; Colord D-Bus service.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
|
(define %colord-activation
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
(mkdir-p "/var/lib/colord")
|
||||||
|
(let ((user (getpwnam "colord")))
|
||||||
|
(chown "/var/lib/colord"
|
||||||
|
(passwd:uid user) (passwd:gid user)))))
|
||||||
|
|
||||||
|
(define %colord-accounts
|
||||||
|
(list (user-group (name "colord") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "colord")
|
||||||
|
(group "colord")
|
||||||
|
(system? #t)
|
||||||
|
(comment "colord daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define (colord-dmd-service colord)
|
||||||
|
"Return a dmd service for COLORD."
|
||||||
|
;; TODO: Remove when D-Bus activation works.
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the colord color management service.")
|
||||||
|
(provision '(colord-daemon))
|
||||||
|
(requirement '(dbus-system udev))
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$colord "/libexec/colord"))))
|
||||||
|
(stop #~(make-kill-destructor)))))
|
||||||
|
|
||||||
|
(define colord-service-type
|
||||||
|
(service-type (name 'colord)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension account-service-type
|
||||||
|
(const %colord-accounts))
|
||||||
|
(service-extension activation-service-type
|
||||||
|
(const %colord-activation))
|
||||||
|
(service-extension dmd-root-service-type
|
||||||
|
colord-dmd-service)
|
||||||
|
|
||||||
|
;; Colord is a D-Bus service that dbus-daemon can
|
||||||
|
;; activate.
|
||||||
|
(service-extension dbus-root-service-type list)
|
||||||
|
|
||||||
|
;; Colord provides "color device" rules for udev.
|
||||||
|
(service-extension udev-service-type list)))))
|
||||||
|
|
||||||
(define* (colord-service #:key (colord colord))
|
(define* (colord-service #:key (colord colord))
|
||||||
"Return a service that runs @command{colord}, a system service with a D-Bus
|
"Return a service that runs @command{colord}, a system service with a D-Bus
|
||||||
interface to manage the color profiles of input and output devices such as
|
interface to manage the color profiles of input and output devices such as
|
||||||
screens and scanners. It is notably used by the GNOME Color Manager graphical
|
screens and scanners. It is notably used by the GNOME Color Manager graphical
|
||||||
tool. See @uref{http://www.freedesktop.org/software/colord/, the colord web
|
tool. See @uref{http://www.freedesktop.org/software/colord/, the colord web
|
||||||
site} for more information."
|
site} for more information."
|
||||||
(service
|
(service colord-service-type colord))
|
||||||
(documentation "Run the colord color management service.")
|
|
||||||
(provision '(colord-daemon))
|
|
||||||
(requirement '(dbus-system udev))
|
|
||||||
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$colord "/libexec/colord"))))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(activate #~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
(mkdir-p "/var/lib/colord")
|
|
||||||
(let ((user (getpwnam "colord")))
|
|
||||||
(chown "/var/lib/colord"
|
|
||||||
(passwd:uid user) (passwd:gid user)))))
|
|
||||||
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "colord")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "colord")
|
|
||||||
(group "colord")
|
|
||||||
(system? #t)
|
|
||||||
(comment "colord daemon user")
|
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell
|
|
||||||
#~(string-append #$shadow "/sbin/nologin")))))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; GeoClue D-Bus service.
|
;;; GeoClue D-Bus service.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
|
;; TODO: Export.
|
||||||
|
(define-record-type* <geoclue-configuration>
|
||||||
|
geoclue-configuration make-geoclue-configuration
|
||||||
|
geoclue-configuration?
|
||||||
|
(geoclue geoclue-configuration-geoclue
|
||||||
|
(default geoclue))
|
||||||
|
(whitelist geoclue-configuration-whitelist)
|
||||||
|
(wifi-geolocation-url geoclue-configuration-wifi-geolocation-url)
|
||||||
|
(submit-data? geoclue-configuration-submit-data?)
|
||||||
|
(wifi-submission-url geoclue-configuration-wifi-submission-url)
|
||||||
|
(submission-nick geoclue-configuration-submission-nick)
|
||||||
|
(applications geoclue-configuration-applications))
|
||||||
|
|
||||||
(define* (geoclue-application name #:key (allowed? #t) system? (users '()))
|
(define* (geoclue-application name #:key (allowed? #t) system? (users '()))
|
||||||
"Configure default GeoClue access permissions for an application. NAME is
|
"Configure default GeoClue access permissions for an application. NAME is
|
||||||
the Desktop ID of the application, without the .desktop part. If ALLOWED? is
|
the Desktop ID of the application, without the .desktop part. If ALLOWED? is
|
||||||
|
@ -311,21 +334,67 @@ users are allowed."
|
||||||
(geoclue-application "epiphany" #:system? #f)
|
(geoclue-application "epiphany" #:system? #f)
|
||||||
(geoclue-application "firefox" #:system? #f)))
|
(geoclue-application "firefox" #:system? #f)))
|
||||||
|
|
||||||
(define* (geoclue-configuration-file #:key whitelist wifi-geolocation-url
|
(define* (geoclue-configuration-file config)
|
||||||
submit-data?
|
|
||||||
wifi-submission-url submission-nick
|
|
||||||
applications)
|
|
||||||
"Return a geoclue configuration file."
|
"Return a geoclue configuration file."
|
||||||
(plain-file "geoclue.conf"
|
(plain-file "geoclue.conf"
|
||||||
(string-append
|
(string-append
|
||||||
"[agent]\n"
|
"[agent]\n"
|
||||||
"whitelist=" (string-join whitelist ";") "\n"
|
"whitelist="
|
||||||
|
(string-join (geoclue-configuration-whitelist config)
|
||||||
|
";") "\n"
|
||||||
"[wifi]\n"
|
"[wifi]\n"
|
||||||
"url=" wifi-geolocation-url "\n"
|
"url=" (geoclue-configuration-wifi-geolocation-url config) "\n"
|
||||||
"submit-data=" (bool submit-data?)
|
"submit-data=" (bool (geoclue-configuration-submit-data? config))
|
||||||
"submission-url=" wifi-submission-url "\n"
|
"submission-url="
|
||||||
"submission-nick=" submission-nick "\n"
|
(geoclue-configuration-wifi-submission-url config) "\n"
|
||||||
(string-join applications "\n"))))
|
"submission-nick="
|
||||||
|
(geoclue-configuration-submission-nick config)
|
||||||
|
"\n"
|
||||||
|
(string-join (geoclue-configuration-applications config)
|
||||||
|
"\n"))))
|
||||||
|
|
||||||
|
(define (geoclue-dbus-service config)
|
||||||
|
(list (wrapped-dbus-service (geoclue-configuration-geoclue config)
|
||||||
|
"libexec/geoclue"
|
||||||
|
"GEOCLUE_CONFIG_FILE"
|
||||||
|
(geoclue-configuration-file config))))
|
||||||
|
|
||||||
|
(define (geoclue-dmd-service config)
|
||||||
|
"Return a GeoClue dmd service for CONFIG."
|
||||||
|
;; TODO: Remove when D-Bus activation works.
|
||||||
|
(let ((geoclue (geoclue-configuration-geoclue config))
|
||||||
|
(config (geoclue-configuration-file config)))
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the GeoClue location service.")
|
||||||
|
(provision '(geoclue-daemon))
|
||||||
|
(requirement '(dbus-system))
|
||||||
|
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$geoclue "/libexec/geoclue"))
|
||||||
|
#:user "geoclue"
|
||||||
|
#:environment-variables
|
||||||
|
(list (string-append "GEOCLUE_CONFIG_FILE=" #$config))))
|
||||||
|
(stop #~(make-kill-destructor))))))
|
||||||
|
|
||||||
|
(define %geoclue-accounts
|
||||||
|
(list (user-group (name "geoclue") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "geoclue")
|
||||||
|
(group "geoclue")
|
||||||
|
(system? #t)
|
||||||
|
(comment "GeoClue daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell "/run/current-system/profile/sbin/nologin"))))
|
||||||
|
|
||||||
|
(define geoclue-service-type
|
||||||
|
(service-type (name 'geoclue)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dbus-root-service-type
|
||||||
|
geoclue-dbus-service)
|
||||||
|
(service-extension dmd-root-service-type
|
||||||
|
geoclue-dmd-service)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %geoclue-accounts))))))
|
||||||
|
|
||||||
(define* (geoclue-service #:key (geoclue geoclue)
|
(define* (geoclue-service #:key (geoclue geoclue)
|
||||||
(whitelist '())
|
(whitelist '())
|
||||||
|
@ -345,70 +414,67 @@ and Epiphany web browsers are able to ask for the user's location, and in the
|
||||||
case of Icecat and Epiphany, both will ask the user for permission first. See
|
case of Icecat and Epiphany, both will ask the user for permission first. See
|
||||||
@uref{https://wiki.freedesktop.org/www/Software/GeoClue/, the geoclue web
|
@uref{https://wiki.freedesktop.org/www/Software/GeoClue/, the geoclue web
|
||||||
site} for more information."
|
site} for more information."
|
||||||
(let ((config (geoclue-configuration-file
|
(service geoclue-service-type
|
||||||
#:whitelist whitelist
|
(geoclue-configuration
|
||||||
#:wifi-geolocation-url wifi-geolocation-url
|
(geoclue geoclue)
|
||||||
#:submit-data? submit-data?
|
(whitelist whitelist)
|
||||||
#:wifi-submission-url wifi-submission-url
|
(wifi-geolocation-url wifi-geolocation-url)
|
||||||
#:submission-nick submission-nick
|
(submit-data? submit-data?)
|
||||||
#:applications applications)))
|
(wifi-submission-url wifi-submission-url)
|
||||||
(service
|
(submission-nick submission-nick)
|
||||||
(documentation "Run the GeoClue location service.")
|
(applications applications))))
|
||||||
(provision '(geoclue-daemon))
|
|
||||||
(requirement '(dbus-system))
|
|
||||||
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$geoclue "/libexec/geoclue"))
|
|
||||||
#:user "geoclue"
|
|
||||||
#:environment-variables
|
|
||||||
(list (string-append "GEOCLUE_CONFIG_FILE=" #$config))))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "geoclue")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "geoclue")
|
|
||||||
(group "geoclue")
|
|
||||||
(system? #t)
|
|
||||||
(comment "GeoClue daemon user")
|
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell
|
|
||||||
"/run/current-system/profile/sbin/nologin")))))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Polkit privilege management service.
|
;;; Polkit privilege management service.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
|
(define %polkit-accounts
|
||||||
|
(list (user-group (name "polkitd") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "polkitd")
|
||||||
|
(group "polkitd")
|
||||||
|
(system? #t)
|
||||||
|
(comment "Polkit daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell "/run/current-system/profile/sbin/nologin"))))
|
||||||
|
|
||||||
|
(define %polkit-pam-services
|
||||||
|
(list (unix-pam-service "polkit-1")))
|
||||||
|
|
||||||
|
(define (polkit-dmd-service polkit)
|
||||||
|
"Return the <dmd-service> for POLKIT."
|
||||||
|
;; TODO: Remove when D-Bus activation works.
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the polkit privilege management service.")
|
||||||
|
(provision '(polkit-daemon))
|
||||||
|
(requirement '(dbus-system))
|
||||||
|
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$polkit "/lib/polkit-1/polkitd"))))
|
||||||
|
(stop #~(make-kill-destructor)))))
|
||||||
|
|
||||||
|
(define polkit-service-type
|
||||||
|
;; TODO: Make it extensible so it can collect policy files from other
|
||||||
|
;; services.
|
||||||
|
(service-type (name 'polkit)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension account-service-type
|
||||||
|
(const %polkit-accounts))
|
||||||
|
(service-extension pam-root-service-type
|
||||||
|
(const %polkit-pam-services))
|
||||||
|
(service-extension dbus-root-service-type
|
||||||
|
list)
|
||||||
|
(service-extension dmd-root-service-type
|
||||||
|
polkit-dmd-service)))))
|
||||||
|
|
||||||
(define* (polkit-service #:key (polkit polkit))
|
(define* (polkit-service #:key (polkit polkit))
|
||||||
"Return a service that runs the @command{polkit} privilege management
|
"Return a service that runs the @command{polkit} privilege management
|
||||||
service. By querying the @command{polkit} service, a privileged system
|
service. By querying the @command{polkit} service, a privileged system
|
||||||
component can know when it should grant additional capabilities to ordinary
|
component can know when it should grant additional capabilities to ordinary
|
||||||
users. For example, an ordinary user can be granted the capability to suspend
|
users. For example, an ordinary user can be granted the capability to suspend
|
||||||
the system if the user is logged in locally."
|
the system if the user is logged in locally."
|
||||||
(service
|
(service polkit-service-type polkit))
|
||||||
(documentation "Run the polkit privilege management service.")
|
|
||||||
(provision '(polkit-daemon))
|
|
||||||
(requirement '(dbus-system))
|
|
||||||
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$polkit "/lib/polkit-1/polkitd"))))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "polkitd")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "polkitd")
|
|
||||||
(group "polkitd")
|
|
||||||
(system? #t)
|
|
||||||
(comment "Polkit daemon user")
|
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell
|
|
||||||
"/run/current-system/profile/sbin/nologin"))))
|
|
||||||
|
|
||||||
(pam-services (list (unix-pam-service "polkit-1")))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
|
@ -418,6 +484,8 @@ the system if the user is logged in locally."
|
||||||
(define-record-type* <elogind-configuration> elogind-configuration
|
(define-record-type* <elogind-configuration> elogind-configuration
|
||||||
make-elogind-configuration
|
make-elogind-configuration
|
||||||
elogind-configuration
|
elogind-configuration
|
||||||
|
(elogind elogind-package
|
||||||
|
(default elogind))
|
||||||
(kill-user-processes? elogind-kill-user-processes?
|
(kill-user-processes? elogind-kill-user-processes?
|
||||||
(default #f))
|
(default #f))
|
||||||
(kill-only-users elogind-kill-only-users
|
(kill-only-users elogind-kill-only-users
|
||||||
|
@ -547,67 +615,62 @@ the system if the user is logged in locally."
|
||||||
("HybridSleepState" (sleep-list elogind-hybrid-sleep-state))
|
("HybridSleepState" (sleep-list elogind-hybrid-sleep-state))
|
||||||
("HybridSleepMode" (sleep-list elogind-hybrid-sleep-mode))))
|
("HybridSleepMode" (sleep-list elogind-hybrid-sleep-mode))))
|
||||||
|
|
||||||
(define* (elogind-service #:key (elogind elogind)
|
(define (elogind-dmd-service config)
|
||||||
(config (elogind-configuration)))
|
"Return a dmd service for elogind, using @var{config}."
|
||||||
|
(let ((config-file (elogind-configuration-file config))
|
||||||
|
(elogind (elogind-package config)))
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the elogind login and seat management service.")
|
||||||
|
(provision '(elogind))
|
||||||
|
(requirement '(dbus-system))
|
||||||
|
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$elogind "/libexec/elogind/elogind"))
|
||||||
|
#:environment-variables
|
||||||
|
(list (string-append "ELOGIND_CONF_FILE=" #$config-file))))
|
||||||
|
(stop #~(make-kill-destructor))))))
|
||||||
|
|
||||||
|
(define elogind-service-type
|
||||||
|
(service-type (name 'elogind)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
elogind-dmd-service)
|
||||||
|
(service-extension dbus-root-service-type
|
||||||
|
(compose list elogind-package))
|
||||||
|
(service-extension udev-service-type
|
||||||
|
(compose list elogind-package))
|
||||||
|
;; TODO: Extend polkit(?) and PAM.
|
||||||
|
))))
|
||||||
|
|
||||||
|
(define* (elogind-service #:key (config (elogind-configuration)))
|
||||||
"Return a service that runs the @command{elogind} login and seat management
|
"Return a service that runs the @command{elogind} login and seat management
|
||||||
service. The @command{elogind} service integrates with PAM to allow other
|
service. The @command{elogind} service integrates with PAM to allow other
|
||||||
system components to know the set of logged-in users as well as their session
|
system components to know the set of logged-in users as well as their session
|
||||||
types (graphical, console, remote, etc.). It can also clean up after users
|
types (graphical, console, remote, etc.). It can also clean up after users
|
||||||
when they log out."
|
when they log out."
|
||||||
(let ((config-file (elogind-configuration-file config)))
|
(service elogind-service-type config))
|
||||||
(service
|
|
||||||
(documentation "Run the elogind login and seat management service.")
|
|
||||||
(provision '(elogind))
|
|
||||||
(requirement '(dbus-system))
|
|
||||||
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$elogind "/libexec/elogind/elogind"))
|
|
||||||
#:environment-variables
|
|
||||||
(list (string-append "ELOGIND_CONF_FILE=" #$config-file))))
|
|
||||||
(stop #~(make-kill-destructor)))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; The default set of desktop services.
|
;;; The default set of desktop services.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(define %desktop-services
|
(define %desktop-services
|
||||||
;; List of services typically useful for a "desktop" use case.
|
;; List of services typically useful for a "desktop" use case.
|
||||||
(cons* (slim-service)
|
(cons* (slim-service)
|
||||||
|
|
||||||
|
;; The D-Bus clique.
|
||||||
(avahi-service)
|
(avahi-service)
|
||||||
(wicd-service)
|
(wicd-service)
|
||||||
(upower-service)
|
(upower-service)
|
||||||
;; FIXME: The colord, geoclue, and polkit services could all be
|
|
||||||
;; bus-activated by default, so they don't run at program startup.
|
|
||||||
;; However, user creation and /var/lib/colord creation happen at
|
|
||||||
;; service activation time, so we currently add them to the set of
|
|
||||||
;; default services.
|
|
||||||
(colord-service)
|
(colord-service)
|
||||||
(geoclue-service)
|
(geoclue-service)
|
||||||
(polkit-service)
|
(polkit-service)
|
||||||
(elogind-service)
|
(elogind-service)
|
||||||
(dbus-service (list avahi wicd upower colord geoclue polkit elogind))
|
(dbus-service)
|
||||||
|
|
||||||
(ntp-service)
|
(ntp-service)
|
||||||
|
|
||||||
(map (lambda (service)
|
%base-services))
|
||||||
(cond
|
|
||||||
;; Provide an nscd ready to use nss-mdns.
|
|
||||||
((memq 'nscd (service-provision service))
|
|
||||||
(nscd-service (nscd-configuration
|
|
||||||
(name-services (list nss-mdns)))))
|
|
||||||
|
|
||||||
;; Add more rules to udev-service.
|
|
||||||
;;
|
|
||||||
;; XXX Keep this in sync with the 'udev-service' call in
|
|
||||||
;; %base-services. Here we intend only to add 'upower',
|
|
||||||
;; 'colord', and 'elogind'.
|
|
||||||
((memq 'udev (service-provision service))
|
|
||||||
(udev-service #:rules
|
|
||||||
(list lvm2 fuse alsa-utils crda
|
|
||||||
upower colord elogind)))
|
|
||||||
|
|
||||||
(else service)))
|
|
||||||
%base-services)))
|
|
||||||
|
|
||||||
;;; desktop.scm ends here
|
;;; desktop.scm ends here
|
||||||
|
|
|
@ -22,13 +22,27 @@
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
#:use-module (guix store)
|
#:use-module (guix store)
|
||||||
#:use-module (guix monads)
|
#:use-module (guix monads)
|
||||||
|
#:use-module (guix records)
|
||||||
#:use-module (guix derivations) ;imported-modules, etc.
|
#:use-module (guix derivations) ;imported-modules, etc.
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu packages admin)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (srfi srfi-34)
|
#:use-module (srfi srfi-34)
|
||||||
#:use-module (srfi srfi-35)
|
#:use-module (srfi srfi-35)
|
||||||
#:export (dmd-configuration-file))
|
#:export (dmd-root-service-type
|
||||||
|
%dmd-root-service
|
||||||
|
dmd-service-type
|
||||||
|
|
||||||
|
dmd-service
|
||||||
|
dmd-service?
|
||||||
|
dmd-service-documentation
|
||||||
|
dmd-service-provision
|
||||||
|
dmd-service-requirement
|
||||||
|
dmd-service-respawn?
|
||||||
|
dmd-service-start
|
||||||
|
dmd-service-stop
|
||||||
|
dmd-service-auto-start?))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;;
|
;;;
|
||||||
|
@ -36,6 +50,68 @@
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
|
||||||
|
(define (dmd-boot-gexp services)
|
||||||
|
(mlet %store-monad ((dmd-conf (dmd-configuration-file services)))
|
||||||
|
(return #~(begin
|
||||||
|
;; Keep track of the booted system.
|
||||||
|
(false-if-exception (delete-file "/run/booted-system"))
|
||||||
|
(symlink (readlink "/run/current-system")
|
||||||
|
"/run/booted-system")
|
||||||
|
|
||||||
|
;; Close any remaining open file descriptors to be on the safe
|
||||||
|
;; side. This must be the very last thing we do, because
|
||||||
|
;; Guile has internal FDs such as 'sleep_pipe' that need to be
|
||||||
|
;; alive.
|
||||||
|
(let loop ((fd 3))
|
||||||
|
(when (< fd 1024)
|
||||||
|
(false-if-exception (close-fdes fd))
|
||||||
|
(loop (+ 1 fd))))
|
||||||
|
|
||||||
|
;; Start dmd.
|
||||||
|
(execl (string-append #$dmd "/bin/dmd")
|
||||||
|
"dmd" "--config" #$dmd-conf)))))
|
||||||
|
|
||||||
|
(define dmd-root-service-type
|
||||||
|
(service-type
|
||||||
|
(name 'dmd-root)
|
||||||
|
;; Extending the root dmd service (aka. PID 1) happens by concatenating the
|
||||||
|
;; list of services provided by the extensions.
|
||||||
|
(compose concatenate)
|
||||||
|
(extend append)
|
||||||
|
(extensions (list (service-extension boot-service-type dmd-boot-gexp)))))
|
||||||
|
|
||||||
|
(define %dmd-root-service
|
||||||
|
;; The root dmd service, aka. PID 1. Its parameter is a list of
|
||||||
|
;; <dmd-service> objects.
|
||||||
|
(service dmd-root-service-type '()))
|
||||||
|
|
||||||
|
(define-syntax-rule (dmd-service-type proc)
|
||||||
|
"Return a <service-type> denoting a simple dmd service--i.e., the type for a
|
||||||
|
service that extends DMD-ROOT-SERVICE-TYPE and nothing else."
|
||||||
|
(service-type
|
||||||
|
(name 'some-dmd-service)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
(compose list proc))))))
|
||||||
|
|
||||||
|
(define-record-type* <dmd-service>
|
||||||
|
dmd-service make-dmd-service
|
||||||
|
dmd-service?
|
||||||
|
(documentation service-documentation ; string
|
||||||
|
(default "[No documentation.]"))
|
||||||
|
(provision service-provision) ; list of symbols
|
||||||
|
(requirement service-requirement ; list of symbols
|
||||||
|
(default '()))
|
||||||
|
(respawn? service-respawn? ; Boolean
|
||||||
|
(default #t))
|
||||||
|
(start service-start) ; g-expression (procedure)
|
||||||
|
(stop service-stop ; g-expression (procedure)
|
||||||
|
(default #~(const #f)))
|
||||||
|
(auto-start? service-auto-start? ; Boolean
|
||||||
|
(default #t)))
|
||||||
|
|
||||||
|
|
||||||
(define (assert-no-duplicates services)
|
(define (assert-no-duplicates services)
|
||||||
"Raise an error if SERVICES provide the same dmd service more than once.
|
"Raise an error if SERVICES provide the same dmd service more than once.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2015 Alex Kost <alezost@gmail.com>
|
;;; Copyright © 2015 Alex Kost <alezost@gmail.com>
|
||||||
|
;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -18,17 +19,65 @@
|
||||||
|
|
||||||
(define-module (gnu services lirc)
|
(define-module (gnu services lirc)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
#:use-module (gnu packages lirc)
|
#:use-module (gnu packages lirc)
|
||||||
#:use-module (guix store)
|
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (guix records)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
#:export (lirc-service))
|
#:export (lirc-service))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;;
|
;;;
|
||||||
;;; LIRC services.
|
;;; LIRC service.
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
(define-record-type* <lirc-configuration>
|
||||||
|
lirc-configuration make-lirc-configuration
|
||||||
|
lirc-configuation?
|
||||||
|
(lirc lirc-configuration-lirc ;<package>
|
||||||
|
(default lirc))
|
||||||
|
(device lirc-configuration-device) ;string
|
||||||
|
(driver lirc-configuration-driver) ;string
|
||||||
|
(config-file lirc-configuration-file) ;string | file-like object
|
||||||
|
(extra-options lirc-configuration-options ;list of strings
|
||||||
|
(default '())))
|
||||||
|
|
||||||
|
(define %lirc-activation
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
(mkdir-p "/var/run/lirc")))
|
||||||
|
|
||||||
|
(define lirc-dmd-service
|
||||||
|
(match-lambda
|
||||||
|
(($ <lirc-configuration> lirc device driver config-file options)
|
||||||
|
(list (dmd-service
|
||||||
|
(provision '(lircd))
|
||||||
|
(documentation "Run the LIRC daemon.")
|
||||||
|
(requirement '(user-processes))
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$lirc "/sbin/lircd")
|
||||||
|
"--nodaemon"
|
||||||
|
#$@(if device
|
||||||
|
#~("--device" #$device)
|
||||||
|
#~())
|
||||||
|
#$@(if driver
|
||||||
|
#~("--driver" #$driver)
|
||||||
|
#~())
|
||||||
|
#$@(if config-file
|
||||||
|
#~(#$config-file)
|
||||||
|
#~())
|
||||||
|
#$@options)))
|
||||||
|
(stop #~(make-kill-destructor)))))))
|
||||||
|
|
||||||
|
(define lirc-service-type
|
||||||
|
(service-type (name 'lirc)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
lirc-dmd-service)
|
||||||
|
(service-extension activation-service-type
|
||||||
|
(const %lirc-activation))))))
|
||||||
|
|
||||||
(define* (lirc-service #:key (lirc lirc)
|
(define* (lirc-service #:key (lirc lirc)
|
||||||
device driver config-file
|
device driver config-file
|
||||||
(extra-options '()))
|
(extra-options '()))
|
||||||
|
@ -40,26 +89,11 @@ The daemon will use specified @var{device}, @var{driver} and
|
||||||
|
|
||||||
Finally, @var{extra-options} is a list of additional command-line options
|
Finally, @var{extra-options} is a list of additional command-line options
|
||||||
passed to @command{lircd}."
|
passed to @command{lircd}."
|
||||||
(service
|
(service lirc-service-type
|
||||||
(provision '(lircd))
|
(lirc-configuration
|
||||||
(documentation "Run the LIRC daemon.")
|
(lirc lirc)
|
||||||
(requirement '(user-processes))
|
(device device) (driver driver)
|
||||||
(start #~(make-forkexec-constructor
|
(config-file config-file)
|
||||||
(list (string-append #$lirc "/sbin/lircd")
|
(extra-options extra-options))))
|
||||||
"--nodaemon"
|
|
||||||
#$@(if device
|
|
||||||
#~("--device" #$device)
|
|
||||||
#~())
|
|
||||||
#$@(if driver
|
|
||||||
#~("--driver" #$driver)
|
|
||||||
#~())
|
|
||||||
#$@(if config-file
|
|
||||||
#~(#$config-file)
|
|
||||||
#~())
|
|
||||||
#$@extra-options)))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(activate #~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
(mkdir-p "/var/run/lirc")))))
|
|
||||||
|
|
||||||
;;; lirc.scm ends here
|
;;; lirc.scm ends here
|
||||||
|
|
|
@ -19,7 +19,10 @@
|
||||||
|
|
||||||
(define-module (gnu services networking)
|
(define-module (gnu services networking)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
|
#:use-module (gnu services dbus)
|
||||||
#:use-module (gnu system shadow)
|
#:use-module (gnu system shadow)
|
||||||
|
#:use-module (gnu system linux) ;PAM
|
||||||
#:use-module (gnu packages admin)
|
#:use-module (gnu packages admin)
|
||||||
#:use-module (gnu packages linux)
|
#:use-module (gnu packages linux)
|
||||||
#:use-module (gnu packages tor)
|
#:use-module (gnu packages tor)
|
||||||
|
@ -27,8 +30,9 @@
|
||||||
#:use-module (gnu packages ntp)
|
#:use-module (gnu packages ntp)
|
||||||
#:use-module (gnu packages wicd)
|
#:use-module (gnu packages wicd)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
#:use-module (guix store)
|
#:use-module (guix records)
|
||||||
#:use-module (srfi srfi-26)
|
#:use-module (srfi srfi-26)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
#:export (%facebook-host-aliases
|
#:export (%facebook-host-aliases
|
||||||
static-networking-service
|
static-networking-service
|
||||||
dhcp-client-service
|
dhcp-client-service
|
||||||
|
@ -78,6 +82,72 @@ fe80::1%lo0 www.connect.facebook.net
|
||||||
fe80::1%lo0 apps.facebook.com\n")
|
fe80::1%lo0 apps.facebook.com\n")
|
||||||
|
|
||||||
|
|
||||||
|
(define-record-type* <static-networking>
|
||||||
|
static-networking make-static-networking
|
||||||
|
static-networking?
|
||||||
|
(interface static-networking-interface)
|
||||||
|
(ip static-networking-ip)
|
||||||
|
(gateway static-networking-gateway)
|
||||||
|
(provision static-networking-provision)
|
||||||
|
(name-servers static-networking-name-servers)
|
||||||
|
(net-tools static-networking-net-tools))
|
||||||
|
|
||||||
|
(define static-networking-service-type
|
||||||
|
(dmd-service-type
|
||||||
|
(match-lambda
|
||||||
|
(($ <static-networking> interface ip gateway provision
|
||||||
|
name-servers net-tools)
|
||||||
|
(let ((loopback? (memq 'loopback provision)))
|
||||||
|
|
||||||
|
;; TODO: Eventually replace 'route' with bindings for the appropriate
|
||||||
|
;; ioctls.
|
||||||
|
(dmd-service
|
||||||
|
|
||||||
|
;; Unless we're providing the loopback interface, wait for udev to be up
|
||||||
|
;; and running so that INTERFACE is actually usable.
|
||||||
|
(requirement (if loopback? '() '(udev)))
|
||||||
|
|
||||||
|
(documentation
|
||||||
|
"Bring up the networking interface using a static IP address.")
|
||||||
|
(provision provision)
|
||||||
|
(start #~(lambda _
|
||||||
|
;; Return #t if successfully started.
|
||||||
|
(let* ((addr (inet-pton AF_INET #$ip))
|
||||||
|
(sockaddr (make-socket-address AF_INET addr 0)))
|
||||||
|
(configure-network-interface #$interface sockaddr
|
||||||
|
(logior IFF_UP
|
||||||
|
#$(if loopback?
|
||||||
|
#~IFF_LOOPBACK
|
||||||
|
0))))
|
||||||
|
#$(if gateway
|
||||||
|
#~(zero? (system* (string-append #$net-tools
|
||||||
|
"/sbin/route")
|
||||||
|
"add" "-net" "default"
|
||||||
|
"gw" #$gateway))
|
||||||
|
#t)
|
||||||
|
#$(if (pair? name-servers)
|
||||||
|
#~(call-with-output-file "/etc/resolv.conf"
|
||||||
|
(lambda (port)
|
||||||
|
(display
|
||||||
|
"# Generated by 'static-networking-service'.\n"
|
||||||
|
port)
|
||||||
|
(for-each (lambda (server)
|
||||||
|
(format port "nameserver ~a~%"
|
||||||
|
server))
|
||||||
|
'#$name-servers)))
|
||||||
|
#t)))
|
||||||
|
(stop #~(lambda _
|
||||||
|
;; Return #f is successfully stopped.
|
||||||
|
(let ((sock (socket AF_INET SOCK_STREAM 0)))
|
||||||
|
(set-network-interface-flags sock #$interface 0)
|
||||||
|
(close-port sock))
|
||||||
|
(not #$(if gateway
|
||||||
|
#~(system* (string-append #$net-tools
|
||||||
|
"/sbin/route")
|
||||||
|
"del" "-net" "default")
|
||||||
|
#t))))
|
||||||
|
(respawn? #f)))))))
|
||||||
|
|
||||||
(define* (static-networking-service interface ip
|
(define* (static-networking-service interface ip
|
||||||
#:key
|
#:key
|
||||||
gateway
|
gateway
|
||||||
|
@ -87,111 +157,70 @@ fe80::1%lo0 apps.facebook.com\n")
|
||||||
"Return a service that starts @var{interface} with address @var{ip}. If
|
"Return a service that starts @var{interface} with address @var{ip}. If
|
||||||
@var{gateway} is true, it must be a string specifying the default network
|
@var{gateway} is true, it must be a string specifying the default network
|
||||||
gateway."
|
gateway."
|
||||||
(define loopback?
|
(service static-networking-service-type
|
||||||
(memq 'loopback provision))
|
(static-networking (interface interface) (ip ip)
|
||||||
|
(gateway gateway)
|
||||||
|
(provision provision)
|
||||||
|
(name-servers name-servers)
|
||||||
|
(net-tools net-tools))))
|
||||||
|
|
||||||
;; TODO: Eventually replace 'route' with bindings for the appropriate
|
(define dhcp-client-service-type
|
||||||
;; ioctls.
|
(dmd-service-type
|
||||||
(service
|
(lambda (dhcp)
|
||||||
|
(define dhclient
|
||||||
|
#~(string-append #$dhcp "/sbin/dhclient"))
|
||||||
|
|
||||||
;; Unless we're providing the loopback interface, wait for udev to be up
|
(define pid-file
|
||||||
;; and running so that INTERFACE is actually usable.
|
"/var/run/dhclient.pid")
|
||||||
(requirement (if loopback? '() '(udev)))
|
|
||||||
|
|
||||||
(documentation
|
(dmd-service
|
||||||
"Bring up the networking interface using a static IP address.")
|
(documentation "Set up networking via DHCP.")
|
||||||
(provision provision)
|
(requirement '(user-processes udev))
|
||||||
(start #~(lambda _
|
|
||||||
;; Return #t if successfully started.
|
;; XXX: Running with '-nw' ("no wait") avoids blocking for a minute when
|
||||||
(let* ((addr (inet-pton AF_INET #$ip))
|
;; networking is unavailable, but also means that the interface is not up
|
||||||
(sockaddr (make-socket-address AF_INET addr 0)))
|
;; yet when 'start' completes. To wait for the interface to be ready, one
|
||||||
(configure-network-interface #$interface sockaddr
|
;; should instead monitor udev events.
|
||||||
(logior IFF_UP
|
(provision '(networking))
|
||||||
#$(if loopback?
|
|
||||||
#~IFF_LOOPBACK
|
(start #~(lambda _
|
||||||
0))))
|
;; When invoked without any arguments, 'dhclient' discovers all
|
||||||
#$(if gateway
|
;; non-loopback interfaces *that are up*. However, the relevant
|
||||||
#~(zero? (system* (string-append #$net-tools
|
;; interfaces are typically down at this point. Thus we perform
|
||||||
"/sbin/route")
|
;; our own interface discovery here.
|
||||||
"add" "-net" "default"
|
(define valid?
|
||||||
"gw" #$gateway))
|
(negate loopback-network-interface?))
|
||||||
#t)
|
(define ifaces
|
||||||
#$(if (pair? name-servers)
|
(filter valid? (all-network-interface-names)))
|
||||||
#~(call-with-output-file "/etc/resolv.conf"
|
|
||||||
(lambda (port)
|
;; XXX: Make sure the interfaces are up so that 'dhclient' can
|
||||||
(display
|
;; actually send/receive over them.
|
||||||
"# Generated by 'static-networking-service'.\n"
|
(for-each set-network-interface-up ifaces)
|
||||||
port)
|
|
||||||
(for-each (lambda (server)
|
(false-if-exception (delete-file #$pid-file))
|
||||||
(format port "nameserver ~a~%"
|
(let ((pid (fork+exec-command
|
||||||
server))
|
(cons* #$dhclient "-nw"
|
||||||
'#$name-servers)))
|
"-pf" #$pid-file ifaces))))
|
||||||
#t)))
|
(and (zero? (cdr (waitpid pid)))
|
||||||
(stop #~(lambda _
|
(let loop ()
|
||||||
;; Return #f is successfully stopped.
|
(catch 'system-error
|
||||||
(let ((sock (socket AF_INET SOCK_STREAM 0)))
|
(lambda ()
|
||||||
(set-network-interface-flags sock #$interface 0)
|
(call-with-input-file #$pid-file read))
|
||||||
(close-port sock))
|
(lambda args
|
||||||
(not #$(if gateway
|
;; 'dhclient' returned before PID-FILE was created,
|
||||||
#~(system* (string-append #$net-tools
|
;; so try again.
|
||||||
"/sbin/route")
|
(let ((errno (system-error-errno args)))
|
||||||
"del" "-net" "default")
|
(if (= ENOENT errno)
|
||||||
#t))))
|
(begin
|
||||||
(respawn? #f)))
|
(sleep 1)
|
||||||
|
(loop))
|
||||||
|
(apply throw args))))))))))
|
||||||
|
(stop #~(make-kill-destructor))))))
|
||||||
|
|
||||||
(define* (dhcp-client-service #:key (dhcp isc-dhcp))
|
(define* (dhcp-client-service #:key (dhcp isc-dhcp))
|
||||||
"Return a service that runs @var{dhcp}, a Dynamic Host Configuration
|
"Return a service that runs @var{dhcp}, a Dynamic Host Configuration
|
||||||
Protocol (DHCP) client, on all the non-loopback network interfaces."
|
Protocol (DHCP) client, on all the non-loopback network interfaces."
|
||||||
|
(service dhcp-client-service-type dhcp))
|
||||||
(define dhclient
|
|
||||||
#~(string-append #$dhcp "/sbin/dhclient"))
|
|
||||||
|
|
||||||
(define pid-file
|
|
||||||
"/var/run/dhclient.pid")
|
|
||||||
|
|
||||||
(service
|
|
||||||
(documentation "Set up networking via DHCP.")
|
|
||||||
(requirement '(user-processes udev))
|
|
||||||
|
|
||||||
;; XXX: Running with '-nw' ("no wait") avoids blocking for a minute when
|
|
||||||
;; networking is unavailable, but also means that the interface is not up
|
|
||||||
;; yet when 'start' completes. To wait for the interface to be ready, one
|
|
||||||
;; should instead monitor udev events.
|
|
||||||
(provision '(networking))
|
|
||||||
|
|
||||||
(start #~(lambda _
|
|
||||||
;; When invoked without any arguments, 'dhclient' discovers all
|
|
||||||
;; non-loopback interfaces *that are up*. However, the relevant
|
|
||||||
;; interfaces are typically down at this point. Thus we perform
|
|
||||||
;; our own interface discovery here.
|
|
||||||
(define valid?
|
|
||||||
(negate loopback-network-interface?))
|
|
||||||
(define ifaces
|
|
||||||
(filter valid? (all-network-interface-names)))
|
|
||||||
|
|
||||||
;; XXX: Make sure the interfaces are up so that 'dhclient' can
|
|
||||||
;; actually send/receive over them.
|
|
||||||
(for-each set-network-interface-up ifaces)
|
|
||||||
|
|
||||||
(false-if-exception (delete-file #$pid-file))
|
|
||||||
(let ((pid (fork+exec-command
|
|
||||||
(cons* #$dhclient "-nw"
|
|
||||||
"-pf" #$pid-file ifaces))))
|
|
||||||
(and (zero? (cdr (waitpid pid)))
|
|
||||||
(let loop ()
|
|
||||||
(catch 'system-error
|
|
||||||
(lambda ()
|
|
||||||
(call-with-input-file #$pid-file read))
|
|
||||||
(lambda args
|
|
||||||
;; 'dhclient' returned before PID-FILE was created,
|
|
||||||
;; so try again.
|
|
||||||
(let ((errno (system-error-errno args)))
|
|
||||||
(if (= ENOENT errno)
|
|
||||||
(begin
|
|
||||||
(sleep 1)
|
|
||||||
(loop))
|
|
||||||
(apply throw args))))))))))
|
|
||||||
(stop #~(make-kill-destructor))))
|
|
||||||
|
|
||||||
(define %ntp-servers
|
(define %ntp-servers
|
||||||
;; Default set of NTP servers.
|
;; Default set of NTP servers.
|
||||||
|
@ -199,19 +228,30 @@ Protocol (DHCP) client, on all the non-loopback network interfaces."
|
||||||
"1.pool.ntp.org"
|
"1.pool.ntp.org"
|
||||||
"2.pool.ntp.org"))
|
"2.pool.ntp.org"))
|
||||||
|
|
||||||
(define* (ntp-service #:key (ntp ntp)
|
|
||||||
(servers %ntp-servers))
|
;;;
|
||||||
"Return a service that runs the daemon from @var{ntp}, the
|
;;; NTP.
|
||||||
@uref{http://www.ntp.org, Network Time Protocol package}. The daemon will
|
;;;
|
||||||
keep the system clock synchronized with that of @var{servers}."
|
|
||||||
;; TODO: Add authentication support.
|
|
||||||
|
|
||||||
(define config
|
;; TODO: Export.
|
||||||
(string-append "driftfile /var/run/ntp.drift\n"
|
(define-record-type* <ntp-configuration>
|
||||||
(string-join (map (cut string-append "server " <>)
|
ntp-configuration make-ntp-configuration
|
||||||
servers)
|
ntp-configuration?
|
||||||
"\n")
|
(ntp ntp-configuration-ntp
|
||||||
"
|
(default ntp))
|
||||||
|
(servers ntp-configuration-servers))
|
||||||
|
|
||||||
|
(define ntp-dmd-service
|
||||||
|
(match-lambda
|
||||||
|
(($ <ntp-configuration> ntp servers)
|
||||||
|
(let ()
|
||||||
|
;; TODO: Add authentication support.
|
||||||
|
(define config
|
||||||
|
(string-append "driftfile /var/run/ntp.drift\n"
|
||||||
|
(string-join (map (cut string-append "server " <>)
|
||||||
|
servers)
|
||||||
|
"\n")
|
||||||
|
"
|
||||||
# Disable status queries as a workaround for CVE-2013-5211:
|
# Disable status queries as a workaround for CVE-2013-5211:
|
||||||
# <http://support.ntp.org/bin/view/Main/SecurityNotice#DRDoS_Amplification_Attack_using>.
|
# <http://support.ntp.org/bin/view/Main/SecurityNotice#DRDoS_Amplification_Attack_using>.
|
||||||
restrict default kod nomodify notrap nopeer noquery
|
restrict default kod nomodify notrap nopeer noquery
|
||||||
|
@ -221,55 +261,154 @@ restrict -6 default kod nomodify notrap nopeer noquery
|
||||||
restrict 127.0.0.1
|
restrict 127.0.0.1
|
||||||
restrict -6 ::1\n"))
|
restrict -6 ::1\n"))
|
||||||
|
|
||||||
(let ((ntpd.conf (plain-file "ntpd.conf" config)))
|
(define ntpd.conf
|
||||||
(service
|
(plain-file "ntpd.conf" config))
|
||||||
(provision '(ntpd))
|
|
||||||
(documentation "Run the Network Time Protocol (NTP) daemon.")
|
(list (dmd-service
|
||||||
(requirement '(user-processes networking))
|
(provision '(ntpd))
|
||||||
(start #~(make-forkexec-constructor
|
(documentation "Run the Network Time Protocol (NTP) daemon.")
|
||||||
(list (string-append #$ntp "/bin/ntpd") "-n"
|
(requirement '(user-processes networking))
|
||||||
"-c" #$ntpd.conf
|
(start #~(make-forkexec-constructor
|
||||||
"-u" "ntpd")))
|
(list (string-append #$ntp "/bin/ntpd") "-n"
|
||||||
(stop #~(make-kill-destructor))
|
"-c" #$ntpd.conf "-u" "ntpd")))
|
||||||
(user-accounts (list (user-account
|
(stop #~(make-kill-destructor))))))))
|
||||||
(name "ntpd")
|
|
||||||
(group "nogroup")
|
(define %ntp-accounts
|
||||||
(system? #t)
|
(list (user-account
|
||||||
(comment "NTP daemon user")
|
(name "ntpd")
|
||||||
(home-directory "/var/empty")
|
(group "nogroup")
|
||||||
(shell
|
(system? #t)
|
||||||
#~(string-append #$shadow "/sbin/nologin"))))))))
|
(comment "NTP daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define ntp-service-type
|
||||||
|
(service-type (name 'ntp)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
ntp-dmd-service)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %ntp-accounts))))))
|
||||||
|
|
||||||
|
(define* (ntp-service #:key (ntp ntp)
|
||||||
|
(servers %ntp-servers))
|
||||||
|
"Return a service that runs the daemon from @var{ntp}, the
|
||||||
|
@uref{http://www.ntp.org, Network Time Protocol package}. The daemon will
|
||||||
|
keep the system clock synchronized with that of @var{servers}."
|
||||||
|
(service ntp-service-type
|
||||||
|
(ntp-configuration (ntp ntp) (servers servers))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Tor.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define %tor-accounts
|
||||||
|
;; User account and groups for Tor.
|
||||||
|
(list (user-group (name "tor") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "tor")
|
||||||
|
(group "tor")
|
||||||
|
(system? #t)
|
||||||
|
(comment "Tor daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define (tor-dmd-service tor)
|
||||||
|
"Return a <dmd-service> running TOR."
|
||||||
|
(let ((torrc (plain-file "torrc" "User tor\n")))
|
||||||
|
(list (dmd-service
|
||||||
|
(provision '(tor))
|
||||||
|
|
||||||
|
;; Tor needs at least one network interface to be up, hence the
|
||||||
|
;; dependency on 'loopback'.
|
||||||
|
(requirement '(user-processes loopback))
|
||||||
|
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$tor "/bin/tor") "-f" #$torrc)))
|
||||||
|
(stop #~(make-kill-destructor))
|
||||||
|
(documentation "Run the Tor anonymous network overlay.")))))
|
||||||
|
|
||||||
|
(define tor-service-type
|
||||||
|
(service-type (name 'tor)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
tor-dmd-service)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %tor-accounts))))))
|
||||||
|
|
||||||
(define* (tor-service #:key (tor tor))
|
(define* (tor-service #:key (tor tor))
|
||||||
"Return a service to run the @uref{https://torproject.org,Tor} daemon.
|
"Return a service to run the @uref{https://torproject.org,Tor} daemon.
|
||||||
|
|
||||||
The daemon runs with the default settings (in particular the default exit
|
The daemon runs with the default settings (in particular the default exit
|
||||||
policy) as the @code{tor} unprivileged user."
|
policy) as the @code{tor} unprivileged user."
|
||||||
(let ((torrc (plain-file "torrc" "User tor\n")))
|
(service tor-service-type tor))
|
||||||
(service
|
|
||||||
(provision '(tor))
|
|
||||||
|
|
||||||
;; Tor needs at least one network interface to be up, hence the
|
|
||||||
;; dependency on 'loopback'.
|
;;;
|
||||||
(requirement '(user-processes loopback))
|
;;; BitlBee.
|
||||||
|
;;;
|
||||||
|
|
||||||
(start #~(make-forkexec-constructor
|
(define-record-type* <bitlbee-configuration>
|
||||||
(list (string-append #$tor "/bin/tor") "-f" #$torrc)))
|
bitlbee-configuration make-bitlbee-configuration
|
||||||
(stop #~(make-kill-destructor))
|
bitlbee-configuration?
|
||||||
|
(bitlbee bitlbee-configuration-bitlbee
|
||||||
|
(default bitlbee))
|
||||||
|
(interface bitlbee-configuration-interface)
|
||||||
|
(port bitlbee-configuration-port)
|
||||||
|
(extra-settings bitlbee-configuration-extra-settings))
|
||||||
|
|
||||||
(user-groups (list (user-group
|
(define bitlbee-dmd-service
|
||||||
(name "tor")
|
(match-lambda
|
||||||
(system? #t))))
|
(($ <bitlbee-configuration> bitlbee interface port extra-settings)
|
||||||
(user-accounts (list (user-account
|
(let ((conf (plain-file "bitlbee.conf"
|
||||||
(name "tor")
|
(string-append "
|
||||||
(group "tor")
|
[settings]
|
||||||
(system? #t)
|
User = bitlbee
|
||||||
(comment "Tor daemon user")
|
ConfigDir = /var/lib/bitlbee
|
||||||
(home-directory "/var/empty")
|
DaemonInterface = " interface "
|
||||||
(shell
|
DaemonPort = " (number->string port) "
|
||||||
#~(string-append #$shadow "/sbin/nologin")))))
|
" extra-settings))))
|
||||||
|
|
||||||
(documentation "Run the Tor anonymous network overlay."))))
|
(list (dmd-service
|
||||||
|
(provision '(bitlbee))
|
||||||
|
(requirement '(user-processes loopback))
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$bitlbee "/sbin/bitlbee")
|
||||||
|
"-n" "-F" "-u" "bitlbee" "-c" #$conf)))
|
||||||
|
(stop #~(make-kill-destructor))))))))
|
||||||
|
|
||||||
|
(define %bitlbee-accounts
|
||||||
|
;; User group and account to run BitlBee.
|
||||||
|
(list (user-group (name "bitlbee") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "bitlbee")
|
||||||
|
(group "bitlbee")
|
||||||
|
(system? #t)
|
||||||
|
(comment "BitlBee daemon user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define %bitlbee-activation
|
||||||
|
;; Activation gexp for BitlBee.
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
|
||||||
|
;; This directory is used to store OTR data.
|
||||||
|
(mkdir-p "/var/lib/bitlbee")
|
||||||
|
(let ((user (getpwnam "bitlbee")))
|
||||||
|
(chown "/var/lib/bitlbee"
|
||||||
|
(passwd:uid user) (passwd:gid user)))))
|
||||||
|
|
||||||
|
(define bitlbee-service-type
|
||||||
|
(service-type (name 'bitlbee)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
bitlbee-dmd-service)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %bitlbee-accounts))
|
||||||
|
(service-extension activation-service-type
|
||||||
|
(const %bitlbee-activation))))))
|
||||||
|
|
||||||
(define* (bitlbee-service #:key (bitlbee bitlbee)
|
(define* (bitlbee-service #:key (bitlbee bitlbee)
|
||||||
(interface "127.0.0.1") (port 6667)
|
(interface "127.0.0.1") (port 6667)
|
||||||
|
@ -284,57 +423,52 @@ come from any networking interface.
|
||||||
|
|
||||||
In addition, @var{extra-settings} specifies a string to append to the
|
In addition, @var{extra-settings} specifies a string to append to the
|
||||||
configuration file."
|
configuration file."
|
||||||
(let ((conf (plain-file "bitlbee.conf"
|
(service bitlbee-service-type
|
||||||
(string-append "
|
(bitlbee-configuration
|
||||||
[settings]
|
(bitlbee bitlbee)
|
||||||
User = bitlbee
|
(interface interface) (port port)
|
||||||
ConfigDir = /var/lib/bitlbee
|
(extra-settings extra-settings))))
|
||||||
DaemonInterface = " interface "
|
|
||||||
DaemonPort = " (number->string port) "
|
|
||||||
" extra-settings))))
|
|
||||||
(service
|
|
||||||
(provision '(bitlbee))
|
|
||||||
(requirement '(user-processes loopback))
|
|
||||||
(activate #~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
|
|
||||||
;; This directory is used to store OTR data.
|
|
||||||
(mkdir-p "/var/lib/bitlbee")
|
;;;
|
||||||
(let ((user (getpwnam "bitlbee")))
|
;;; Wicd.
|
||||||
(chown "/var/lib/bitlbee"
|
;;;
|
||||||
(passwd:uid user) (passwd:gid user)))))
|
|
||||||
(start #~(make-forkexec-constructor
|
(define %wicd-activation
|
||||||
(list (string-append #$bitlbee "/sbin/bitlbee")
|
;; Activation gexp for Wicd.
|
||||||
"-n" "-F" "-u" "bitlbee" "-c" #$conf)))
|
#~(begin
|
||||||
(stop #~(make-kill-destructor))
|
(use-modules (guix build utils))
|
||||||
(user-groups (list (user-group (name "bitlbee") (system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
(mkdir-p "/etc/wicd")
|
||||||
(name "bitlbee")
|
(let ((file-name "/etc/wicd/dhclient.conf.template.default"))
|
||||||
(group "bitlbee")
|
(unless (file-exists? file-name)
|
||||||
(system? #t)
|
(copy-file (string-append #$wicd file-name)
|
||||||
(comment "BitlBee daemon user")
|
file-name)))))
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell #~(string-append #$shadow
|
(define (wicd-dmd-service wicd)
|
||||||
"/sbin/nologin"))))))))
|
"Return a dmd service for WICD."
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Run the Wicd network manager.")
|
||||||
|
(provision '(networking))
|
||||||
|
(requirement '(user-processes dbus-system loopback))
|
||||||
|
(start #~(make-forkexec-constructor
|
||||||
|
(list (string-append #$wicd "/sbin/wicd")
|
||||||
|
"--no-daemon")))
|
||||||
|
(stop #~(make-kill-destructor)))))
|
||||||
|
|
||||||
|
(define wicd-service-type
|
||||||
|
(service-type (name 'wicd)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
wicd-dmd-service)
|
||||||
|
(service-extension dbus-root-service-type
|
||||||
|
list)
|
||||||
|
(service-extension activation-service-type
|
||||||
|
(const %wicd-activation))))))
|
||||||
|
|
||||||
(define* (wicd-service #:key (wicd wicd))
|
(define* (wicd-service #:key (wicd wicd))
|
||||||
"Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network
|
"Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network
|
||||||
manager that aims to simplify wired and wireless networking."
|
manager that aims to simplify wired and wireless networking."
|
||||||
(service
|
(service wicd-service-type wicd))
|
||||||
(documentation "Run the Wicd network manager.")
|
|
||||||
(provision '(networking))
|
|
||||||
(requirement '(user-processes dbus-system loopback))
|
|
||||||
(start #~(make-forkexec-constructor
|
|
||||||
(list (string-append #$wicd "/sbin/wicd")
|
|
||||||
"--no-daemon")))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(activate
|
|
||||||
#~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
(mkdir-p "/etc/wicd")
|
|
||||||
(let ((file-name "/etc/wicd/dhclient.conf.template.default"))
|
|
||||||
(unless (file-exists? file-name)
|
|
||||||
(copy-file (string-append #$wicd file-name)
|
|
||||||
file-name)))))))
|
|
||||||
|
|
||||||
;;; networking.scm ends here
|
;;; networking.scm ends here
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
|
|
||||||
(define-module (gnu services ssh)
|
(define-module (gnu services ssh)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
#:use-module (guix store)
|
#:use-module (guix records)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
#:use-module (gnu system linux) ; 'pam-service'
|
#:use-module (gnu system linux) ; 'pam-service'
|
||||||
#:use-module (gnu packages lsh)
|
#:use-module (gnu packages lsh)
|
||||||
#:export (lsh-service))
|
#:export (lsh-service))
|
||||||
|
@ -30,11 +31,32 @@
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
;; TODO: Export.
|
||||||
|
(define-record-type* <lsh-configuration>
|
||||||
|
lsh-configuration make-lsh-configuration
|
||||||
|
lsh-configuration?
|
||||||
|
(lsh lsh-configuration-lsh
|
||||||
|
(default lsh))
|
||||||
|
(daemonic? lsh-configuration-daemonic?)
|
||||||
|
(host-key lsh-configuration-host-key)
|
||||||
|
(interfaces lsh-configuration-interfaces)
|
||||||
|
(port-number lsh-configuration-port-number)
|
||||||
|
(allow-empty-passwords? lsh-configuration-allow-empty-passwords?)
|
||||||
|
(root-login? lsh-configuration-root-login?)
|
||||||
|
(syslog-output? lsh-configuration-syslog-output?)
|
||||||
|
(pid-file? lsh-configuration-pid-file?)
|
||||||
|
(pid-file lsh-configuration-pid-file)
|
||||||
|
(x11-forwarding? lsh-configuration-x11-forwarding?)
|
||||||
|
(tcp/ip-forwarding? lsh-configuration-tcp/ip-forwarding?)
|
||||||
|
(password-authentication? lsh-configuration-password-authentication?)
|
||||||
|
(public-key-authentication? lsh-configuration-public-key-authentication?)
|
||||||
|
(initialize? lsh-configuration-initialize?))
|
||||||
|
|
||||||
(define %yarrow-seed
|
(define %yarrow-seed
|
||||||
"/var/spool/lsh/yarrow-seed-file")
|
"/var/spool/lsh/yarrow-seed-file")
|
||||||
|
|
||||||
(define (activation lsh host-key)
|
(define (lsh-initialization lsh host-key)
|
||||||
"Return the gexp to activate the LSH service for HOST-KEY."
|
"Return the gexp to initialize the LSH service for HOST-KEY."
|
||||||
#~(begin
|
#~(begin
|
||||||
(unless (file-exists? #$%yarrow-seed)
|
(unless (file-exists? #$%yarrow-seed)
|
||||||
(system* (string-append #$lsh "/bin/lsh-make-seed")
|
(system* (string-append #$lsh "/bin/lsh-make-seed")
|
||||||
|
@ -70,6 +92,88 @@
|
||||||
(waitpid keygen)
|
(waitpid keygen)
|
||||||
(waitpid write-key))))))))))
|
(waitpid write-key))))))))))
|
||||||
|
|
||||||
|
(define (lsh-activation config)
|
||||||
|
"Return the activation gexp for CONFIG."
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
(mkdir-p "/var/spool/lsh")
|
||||||
|
#$(if (lsh-configuration-initialize? config)
|
||||||
|
(lsh-initialization (lsh-configuration-lsh config)
|
||||||
|
(lsh-configuration-host-key config))
|
||||||
|
#t)))
|
||||||
|
|
||||||
|
(define (lsh-dmd-service config)
|
||||||
|
"Return a <dmd-service> for lsh with CONFIG."
|
||||||
|
(define lsh (lsh-configuration-lsh config))
|
||||||
|
(define pid-file (lsh-configuration-pid-file config))
|
||||||
|
(define pid-file? (lsh-configuration-pid-file? config))
|
||||||
|
(define daemonic? (lsh-configuration-daemonic? config))
|
||||||
|
(define interfaces (lsh-configuration-interfaces config))
|
||||||
|
|
||||||
|
(define lsh-command
|
||||||
|
(append
|
||||||
|
(cons #~(string-append #$lsh "/sbin/lshd")
|
||||||
|
(if daemonic?
|
||||||
|
(let ((syslog (if (lsh-configuration-syslog-output? config)
|
||||||
|
'()
|
||||||
|
(list "--no-syslog"))))
|
||||||
|
(cons "--daemonic"
|
||||||
|
(if pid-file?
|
||||||
|
(cons #~(string-append "--pid-file=" #$pid-file)
|
||||||
|
syslog)
|
||||||
|
(cons "--no-pid-file" syslog))))
|
||||||
|
(if pid-file?
|
||||||
|
(list #~(string-append "--pid-file=" #$pid-file))
|
||||||
|
'())))
|
||||||
|
(cons* #~(string-append "--host-key="
|
||||||
|
#$(lsh-configuration-host-key config))
|
||||||
|
#~(string-append "--password-helper=" #$lsh "/sbin/lsh-pam-checkpw")
|
||||||
|
#~(string-append "--subsystems=sftp=" #$lsh "/sbin/sftp-server")
|
||||||
|
"-p" (number->string (lsh-configuration-port-number config))
|
||||||
|
(if (lsh-configuration-password-authentication? config)
|
||||||
|
"--password" "--no-password")
|
||||||
|
(if (lsh-configuration-public-key-authentication? config)
|
||||||
|
"--publickey" "--no-publickey")
|
||||||
|
(if (lsh-configuration-root-login? config)
|
||||||
|
"--root-login" "--no-root-login")
|
||||||
|
(if (lsh-configuration-x11-forwarding? config)
|
||||||
|
"--x11-forward" "--no-x11-forward")
|
||||||
|
(if (lsh-configuration-tcp/ip-forwarding? config)
|
||||||
|
"--tcpip-forward" "--no-tcpip-forward")
|
||||||
|
(if (null? interfaces)
|
||||||
|
'()
|
||||||
|
(list (string-append "--interfaces="
|
||||||
|
(string-join interfaces ",")))))))
|
||||||
|
|
||||||
|
(define requires
|
||||||
|
(if (and daemonic? (lsh-configuration-syslog-output? config))
|
||||||
|
'(networking syslogd)
|
||||||
|
'(networking)))
|
||||||
|
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "GNU lsh SSH server")
|
||||||
|
(provision '(ssh-daemon))
|
||||||
|
(requirement requires)
|
||||||
|
(start #~(make-forkexec-constructor (list #$@lsh-command)))
|
||||||
|
(stop #~(make-kill-destructor)))))
|
||||||
|
|
||||||
|
(define (lsh-pam-services config)
|
||||||
|
"Return a list of <pam-services> for lshd with CONFIG."
|
||||||
|
(list (unix-pam-service
|
||||||
|
"lshd"
|
||||||
|
#:allow-empty-passwords?
|
||||||
|
(lsh-configuration-allow-empty-passwords? config))))
|
||||||
|
|
||||||
|
(define lsh-service-type
|
||||||
|
(service-type (name 'lsh)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
lsh-dmd-service)
|
||||||
|
(service-extension pam-root-service-type
|
||||||
|
lsh-pam-services)
|
||||||
|
(service-extension activation-service-type
|
||||||
|
lsh-activation)))))
|
||||||
|
|
||||||
(define* (lsh-service #:key
|
(define* (lsh-service #:key
|
||||||
(lsh lsh)
|
(lsh lsh)
|
||||||
(daemonic? #t)
|
(daemonic? #t)
|
||||||
|
@ -114,58 +218,20 @@ passwords, and @var{root-login?} specifies whether to accept log-ins as
|
||||||
root.
|
root.
|
||||||
|
|
||||||
The other options should be self-descriptive."
|
The other options should be self-descriptive."
|
||||||
(define lsh-command
|
(service lsh-service-type
|
||||||
(append
|
(lsh-configuration (lsh lsh) (daemonic? daemonic?)
|
||||||
(cons #~(string-append #$lsh "/sbin/lshd")
|
(host-key host-key) (interfaces interfaces)
|
||||||
(if daemonic?
|
(port-number port-number)
|
||||||
(let ((syslog (if syslog-output? '()
|
(allow-empty-passwords? allow-empty-passwords?)
|
||||||
(list "--no-syslog"))))
|
(root-login? root-login?)
|
||||||
(cons "--daemonic"
|
(syslog-output? syslog-output?)
|
||||||
(if pid-file?
|
(pid-file? pid-file?) (pid-file pid-file)
|
||||||
(cons #~(string-append "--pid-file=" #$pid-file)
|
(x11-forwarding? x11-forwarding?)
|
||||||
syslog)
|
(tcp/ip-forwarding? tcp/ip-forwarding?)
|
||||||
(cons "--no-pid-file" syslog))))
|
(password-authentication?
|
||||||
(if pid-file?
|
password-authentication?)
|
||||||
(list #~(string-append "--pid-file=" #$pid-file))
|
(public-key-authentication?
|
||||||
'())))
|
public-key-authentication?)
|
||||||
(cons* #~(string-append "--host-key=" #$host-key)
|
(initialize? initialize?))))
|
||||||
#~(string-append "--password-helper=" #$lsh "/sbin/lsh-pam-checkpw")
|
|
||||||
#~(string-append "--subsystems=sftp=" #$lsh "/sbin/sftp-server")
|
|
||||||
"-p" (number->string port-number)
|
|
||||||
(if password-authentication? "--password" "--no-password")
|
|
||||||
(if public-key-authentication?
|
|
||||||
"--publickey" "--no-publickey")
|
|
||||||
(if root-login?
|
|
||||||
"--root-login" "--no-root-login")
|
|
||||||
(if x11-forwarding?
|
|
||||||
"--x11-forward" "--no-x11-forward")
|
|
||||||
(if tcp/ip-forwarding?
|
|
||||||
"--tcpip-forward" "--no-tcpip-forward")
|
|
||||||
(if (null? interfaces)
|
|
||||||
'()
|
|
||||||
(list (string-append "--interfaces="
|
|
||||||
(string-join interfaces ",")))))))
|
|
||||||
|
|
||||||
(define requires
|
|
||||||
(if (and daemonic? syslog-output?)
|
|
||||||
'(networking syslogd)
|
|
||||||
'(networking)))
|
|
||||||
|
|
||||||
(service
|
|
||||||
(documentation "GNU lsh SSH server")
|
|
||||||
(provision '(ssh-daemon))
|
|
||||||
(requirement requires)
|
|
||||||
(start #~(make-forkexec-constructor (list #$@lsh-command)))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(pam-services
|
|
||||||
(list (unix-pam-service
|
|
||||||
"lshd"
|
|
||||||
#:allow-empty-passwords? allow-empty-passwords?)))
|
|
||||||
(activate #~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
(mkdir-p "/var/spool/lsh")
|
|
||||||
#$(if initialize?
|
|
||||||
(activation lsh host-key)
|
|
||||||
#t)))))
|
|
||||||
|
|
||||||
;;; ssh.scm ends here
|
;;; ssh.scm ends here
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2015 David Thompson <davet@gnu.org>
|
;;; Copyright © 2015 David Thompson <davet@gnu.org>
|
||||||
|
;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -18,12 +19,13 @@
|
||||||
|
|
||||||
(define-module (gnu services web)
|
(define-module (gnu services web)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
#:use-module (gnu system shadow)
|
#:use-module (gnu system shadow)
|
||||||
#:use-module (gnu packages admin)
|
#:use-module (gnu packages admin)
|
||||||
#:use-module (gnu packages web)
|
#:use-module (gnu packages web)
|
||||||
#:use-module (guix records)
|
#:use-module (guix records)
|
||||||
#:use-module (guix store)
|
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
#:export (nginx-service))
|
#:export (nginx-service))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
|
@ -32,6 +34,14 @@
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
(define-record-type* <nginx-configuration>
|
||||||
|
nginx-configuration make-nginx-configuration
|
||||||
|
nginx-configuration?
|
||||||
|
(nginx nginx-configuration-nginx) ;<package>
|
||||||
|
(log-directory nginx-configuration-log-directory) ;string
|
||||||
|
(run-directory nginx-configuration-run-directory) ;string
|
||||||
|
(file nginx-configuration-file)) ;string | file-like
|
||||||
|
|
||||||
(define (default-nginx-config log-directory run-directory)
|
(define (default-nginx-config log-directory run-directory)
|
||||||
(plain-file "nginx.conf"
|
(plain-file "nginx.conf"
|
||||||
(string-append
|
(string-append
|
||||||
|
@ -45,6 +55,58 @@
|
||||||
"}\n"
|
"}\n"
|
||||||
"events {}\n")))
|
"events {}\n")))
|
||||||
|
|
||||||
|
(define %nginx-accounts
|
||||||
|
(list (user-group (name "nginx") (system? #t))
|
||||||
|
(user-account
|
||||||
|
(name "nginx")
|
||||||
|
(group "nginx")
|
||||||
|
(system? #t)
|
||||||
|
(comment "nginx server user")
|
||||||
|
(home-directory "/var/empty")
|
||||||
|
(shell #~(string-append #$shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
|
(define nginx-activation
|
||||||
|
(match-lambda
|
||||||
|
(($ <nginx-configuration> nginx log-directory run-directory config-file)
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils))
|
||||||
|
|
||||||
|
(format #t "creating nginx log directory '~a'~%" #$log-directory)
|
||||||
|
(mkdir-p #$log-directory)
|
||||||
|
(format #t "creating nginx run directory '~a'~%" #$run-directory)
|
||||||
|
(mkdir-p #$run-directory)
|
||||||
|
;; Check configuration file syntax.
|
||||||
|
(system* (string-append #$nginx "/bin/nginx")
|
||||||
|
"-c" #$config-file "-t")))))
|
||||||
|
|
||||||
|
(define nginx-dmd-service
|
||||||
|
(match-lambda
|
||||||
|
(($ <nginx-configuration> nginx log-directory run-directory config-file)
|
||||||
|
(let* ((nginx-binary #~(string-append #$nginx "/sbin/nginx"))
|
||||||
|
(nginx-action
|
||||||
|
(lambda args
|
||||||
|
#~(lambda _
|
||||||
|
(zero?
|
||||||
|
(system* #$nginx-binary "-c" #$config-file #$@args))))))
|
||||||
|
|
||||||
|
;; TODO: Add 'reload' action.
|
||||||
|
(list (dmd-service
|
||||||
|
(provision '(nginx))
|
||||||
|
(documentation "Run the nginx daemon.")
|
||||||
|
(requirement '(user-processes loopback))
|
||||||
|
(start (nginx-action "-p" run-directory))
|
||||||
|
(stop (nginx-action "-s" "stop"))))))))
|
||||||
|
|
||||||
|
(define nginx-service-type
|
||||||
|
(service-type (name 'nginx)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
nginx-dmd-service)
|
||||||
|
(service-extension activation-service-type
|
||||||
|
nginx-activation)
|
||||||
|
(service-extension account-service-type
|
||||||
|
(const %nginx-accounts))))))
|
||||||
|
|
||||||
(define* (nginx-service #:key (nginx nginx)
|
(define* (nginx-service #:key (nginx nginx)
|
||||||
(log-directory "/var/log/nginx")
|
(log-directory "/var/log/nginx")
|
||||||
(run-directory "/var/run/nginx")
|
(run-directory "/var/run/nginx")
|
||||||
|
@ -54,41 +116,9 @@
|
||||||
|
|
||||||
The nginx daemon loads its runtime configuration from CONFIG-FIGLE, stores log
|
The nginx daemon loads its runtime configuration from CONFIG-FIGLE, stores log
|
||||||
files in LOG-DIRECTORY, and stores temporary runtime files in RUN-DIRECTORY."
|
files in LOG-DIRECTORY, and stores temporary runtime files in RUN-DIRECTORY."
|
||||||
(define nginx-binary
|
(service nginx-service-type
|
||||||
#~(string-append #$nginx "/sbin/nginx"))
|
(nginx-configuration
|
||||||
|
(nginx nginx)
|
||||||
(define (nginx-action . args)
|
(log-directory log-directory)
|
||||||
#~(lambda _
|
(run-directory run-directory)
|
||||||
(zero?
|
(file config-file))))
|
||||||
(system* #$nginx-binary "-c" #$config-file #$@args))))
|
|
||||||
|
|
||||||
(define activate
|
|
||||||
#~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
(format #t "creating nginx log directory '~a'~%" #$log-directory)
|
|
||||||
(mkdir-p #$log-directory)
|
|
||||||
(format #t "creating nginx run directory '~a'~%" #$run-directory)
|
|
||||||
(mkdir-p #$run-directory)
|
|
||||||
;; Check configuration file syntax.
|
|
||||||
(system* #$nginx-binary "-c" #$config-file "-t")))
|
|
||||||
|
|
||||||
(define nologin #~(string-append #$shadow "/sbin/nologin"))
|
|
||||||
|
|
||||||
;; TODO: Add 'reload' action.
|
|
||||||
(service
|
|
||||||
(provision '(nginx))
|
|
||||||
(documentation "Run the nginx daemon.")
|
|
||||||
(requirement '(user-processes loopback))
|
|
||||||
(start (nginx-action "-p" run-directory))
|
|
||||||
(stop (nginx-action "-s" "stop"))
|
|
||||||
(activate activate)
|
|
||||||
(user-groups (list (user-group
|
|
||||||
(name "nginx")
|
|
||||||
(system? #t))))
|
|
||||||
(user-accounts (list (user-account
|
|
||||||
(name "nginx")
|
|
||||||
(group "nginx")
|
|
||||||
(system? #t)
|
|
||||||
(comment "nginx server user")
|
|
||||||
(home-directory "/var/empty")
|
|
||||||
(shell nologin))))))
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
(define-module (gnu services xorg)
|
(define-module (gnu services xorg)
|
||||||
#:use-module (gnu artwork)
|
#:use-module (gnu artwork)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
#:use-module (gnu system linux) ; 'pam-service'
|
#:use-module (gnu system linux) ; 'pam-service'
|
||||||
#:use-module ((gnu packages base) #:select (canonical-package))
|
#:use-module ((gnu packages base) #:select (canonical-package))
|
||||||
#:use-module (gnu packages guile)
|
#:use-module (gnu packages guile)
|
||||||
|
@ -212,6 +213,95 @@ which should be passed to this script as the first argument. If not, the
|
||||||
;; contains the actual theme files.
|
;; contains the actual theme files.
|
||||||
"0.x")
|
"0.x")
|
||||||
|
|
||||||
|
(define-record-type* <slim-configuration>
|
||||||
|
slim-configuration make-slim-configuration
|
||||||
|
slim-configuration?
|
||||||
|
(slim slim-configuration-slim
|
||||||
|
(default slim))
|
||||||
|
(allow-empty-passwords? slim-configuration-allow-empty-passwords?)
|
||||||
|
(auto-login? slim-configuration-auto-login?)
|
||||||
|
(default-user slim-configuration-default-user)
|
||||||
|
(theme slim-configuration-theme)
|
||||||
|
(theme-name slim-configuration-theme-name)
|
||||||
|
(xauth slim-configuration-xauth
|
||||||
|
(default xauth))
|
||||||
|
(dmd slim-configuration-dmd
|
||||||
|
(default dmd))
|
||||||
|
(bash slim-configuration-bash
|
||||||
|
(default bash))
|
||||||
|
(auto-login-session slim-configuration-auto-login-session)
|
||||||
|
(startx slim-configuration-startx))
|
||||||
|
|
||||||
|
(define (slim-pam-service config)
|
||||||
|
"Return a PAM service for @command{slim}."
|
||||||
|
(list (unix-pam-service
|
||||||
|
"slim"
|
||||||
|
#:allow-empty-passwords?
|
||||||
|
(slim-configuration-allow-empty-passwords? config))))
|
||||||
|
|
||||||
|
(define (slim-dmd-service config)
|
||||||
|
(define slim.cfg
|
||||||
|
(let ((xinitrc (xinitrc #:fallback-session
|
||||||
|
(slim-configuration-auto-login-session config)))
|
||||||
|
(slim (slim-configuration-slim config))
|
||||||
|
(xauth (slim-configuration-xauth config))
|
||||||
|
(startx (slim-configuration-startx config))
|
||||||
|
(dmd (slim-configuration-dmd config))
|
||||||
|
(theme-name (slim-configuration-theme-name config)))
|
||||||
|
(mixed-text-file "slim.cfg" "
|
||||||
|
default_path /run/current-system/profile/bin
|
||||||
|
default_xserver " startx "
|
||||||
|
xserver_arguments :0 vt7
|
||||||
|
xauth_path " xauth "/bin/xauth
|
||||||
|
authfile /var/run/slim.auth
|
||||||
|
|
||||||
|
# The login command. '%session' is replaced by the chosen session name, one
|
||||||
|
# of the names specified in the 'sessions' setting: 'wmaker', 'xfce', etc.
|
||||||
|
login_cmd exec " xinitrc " %session
|
||||||
|
sessiondir /run/current-system/profile/share/xsessions
|
||||||
|
session_msg session (F1 to change):
|
||||||
|
|
||||||
|
halt_cmd " dmd "/sbin/halt
|
||||||
|
reboot_cmd " dmd "/sbin/reboot\n"
|
||||||
|
(if (slim-configuration-auto-login? config)
|
||||||
|
(string-append "auto_login yes\ndefault_user "
|
||||||
|
(slim-configuration-default-user config) "\n")
|
||||||
|
"")
|
||||||
|
(if theme-name
|
||||||
|
(string-append "current_theme " theme-name "\n")
|
||||||
|
""))))
|
||||||
|
|
||||||
|
(define theme
|
||||||
|
(slim-configuration-theme config))
|
||||||
|
|
||||||
|
(list (dmd-service
|
||||||
|
(documentation "Xorg display server")
|
||||||
|
(provision '(xorg-server))
|
||||||
|
(requirement '(user-processes host-name udev))
|
||||||
|
(start
|
||||||
|
#~(lambda ()
|
||||||
|
;; A stale lock file can prevent SLiM from starting, so remove it to
|
||||||
|
;; be on the safe side.
|
||||||
|
(false-if-exception (delete-file "/var/run/slim.lock"))
|
||||||
|
|
||||||
|
(fork+exec-command
|
||||||
|
(list (string-append #$slim "/bin/slim") "-nodaemon")
|
||||||
|
#:environment-variables
|
||||||
|
(list (string-append "SLIM_CFGFILE=" #$slim.cfg)
|
||||||
|
#$@(if theme
|
||||||
|
(list #~(string-append "SLIM_THEMESDIR=" #$theme))
|
||||||
|
#~())))))
|
||||||
|
(stop #~(make-kill-destructor))
|
||||||
|
(respawn? #t))))
|
||||||
|
|
||||||
|
(define slim-service-type
|
||||||
|
(service-type (name 'slim)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension dmd-root-service-type
|
||||||
|
slim-dmd-service)
|
||||||
|
(service-extension pam-root-service-type
|
||||||
|
slim-pam-service)))))
|
||||||
|
|
||||||
(define* (slim-service #:key (slim slim)
|
(define* (slim-service #:key (slim slim)
|
||||||
(allow-empty-passwords? #t) auto-login?
|
(allow-empty-passwords? #t) auto-login?
|
||||||
(default-user "")
|
(default-user "")
|
||||||
|
@ -246,54 +336,14 @@ If @var{theme} is @code{#f}, the use the default log-in theme; otherwise
|
||||||
@var{theme} must be a gexp denoting the name of a directory containing the
|
@var{theme} must be a gexp denoting the name of a directory containing the
|
||||||
theme to use. In that case, @var{theme-name} specifies the name of the
|
theme to use. In that case, @var{theme-name} specifies the name of the
|
||||||
theme."
|
theme."
|
||||||
|
(service slim-service-type
|
||||||
(define slim.cfg
|
(slim-configuration
|
||||||
(let ((xinitrc (xinitrc #:fallback-session auto-login-session)))
|
(slim slim)
|
||||||
(mixed-text-file "slim.cfg" "
|
(allow-empty-passwords? allow-empty-passwords?)
|
||||||
default_path /run/current-system/profile/bin
|
(auto-login? auto-login?) (default-user default-user)
|
||||||
default_xserver " startx "
|
(theme theme) (theme-name theme-name)
|
||||||
xserver_arguments :0 vt7
|
(xauth xauth) (dmd dmd) (bash bash)
|
||||||
xauth_path " xauth "/bin/xauth
|
(auto-login-session auto-login-session)
|
||||||
authfile /var/run/slim.auth
|
(startx startx))))
|
||||||
|
|
||||||
# The login command. '%session' is replaced by the chosen session name, one
|
|
||||||
# of the names specified in the 'sessions' setting: 'wmaker', 'xfce', etc.
|
|
||||||
login_cmd exec " xinitrc " %session
|
|
||||||
sessiondir /run/current-system/profile/share/xsessions
|
|
||||||
session_msg session (F1 to change):
|
|
||||||
|
|
||||||
halt_cmd " dmd "/sbin/halt
|
|
||||||
reboot_cmd " dmd "/sbin/reboot\n"
|
|
||||||
(if auto-login?
|
|
||||||
(string-append "auto_login yes\ndefault_user " default-user "\n")
|
|
||||||
"")
|
|
||||||
(if theme-name
|
|
||||||
(string-append "current_theme " theme-name "\n")
|
|
||||||
""))))
|
|
||||||
|
|
||||||
(service
|
|
||||||
(documentation "Xorg display server")
|
|
||||||
(provision '(xorg-server))
|
|
||||||
(requirement '(user-processes host-name udev))
|
|
||||||
(start
|
|
||||||
#~(lambda ()
|
|
||||||
;; A stale lock file can prevent SLiM from starting, so remove it
|
|
||||||
;; to be on the safe side.
|
|
||||||
(false-if-exception (delete-file "/var/run/slim.lock"))
|
|
||||||
|
|
||||||
(fork+exec-command
|
|
||||||
(list (string-append #$slim "/bin/slim") "-nodaemon")
|
|
||||||
#:environment-variables
|
|
||||||
(list (string-append "SLIM_CFGFILE=" #$slim.cfg)
|
|
||||||
#$@(if theme
|
|
||||||
(list #~(string-append "SLIM_THEMESDIR=" #$theme))
|
|
||||||
#~())))))
|
|
||||||
(stop #~(make-kill-destructor))
|
|
||||||
(respawn? #t)
|
|
||||||
(pam-services
|
|
||||||
;; Tell PAM about 'slim'.
|
|
||||||
(list (unix-pam-service
|
|
||||||
"slim"
|
|
||||||
#:allow-empty-passwords? allow-empty-passwords?)))))
|
|
||||||
|
|
||||||
;;; xorg.scm ends here
|
;;; xorg.scm ends here
|
||||||
|
|
459
gnu/system.scm
459
gnu/system.scm
|
@ -87,8 +87,6 @@
|
||||||
operating-system-locale-directory
|
operating-system-locale-directory
|
||||||
operating-system-boot-script
|
operating-system-boot-script
|
||||||
|
|
||||||
file-union
|
|
||||||
|
|
||||||
local-host-aliases
|
local-host-aliases
|
||||||
%setuid-programs
|
%setuid-programs
|
||||||
%base-packages
|
%base-packages
|
||||||
|
@ -160,41 +158,6 @@
|
||||||
(sudoers-file operating-system-sudoers-file ; file-like
|
(sudoers-file operating-system-sudoers-file ; file-like
|
||||||
(default %sudoers-specification)))
|
(default %sudoers-specification)))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
|
||||||
;;; Derivation.
|
|
||||||
;;;
|
|
||||||
|
|
||||||
(define* (file-union name files)
|
|
||||||
"Return a derivation that builds a directory containing all of FILES. Each
|
|
||||||
item in FILES must be a list where the first element is the file name to use
|
|
||||||
in the new directory, and the second element is a gexp denoting the target
|
|
||||||
file."
|
|
||||||
(define builder
|
|
||||||
#~(begin
|
|
||||||
(mkdir #$output)
|
|
||||||
(chdir #$output)
|
|
||||||
#$@(map (match-lambda
|
|
||||||
((target source)
|
|
||||||
#~(symlink #$source #$target)))
|
|
||||||
files)))
|
|
||||||
|
|
||||||
(gexp->derivation name builder))
|
|
||||||
|
|
||||||
(define (directory-union name things)
|
|
||||||
"Return a directory that is the union of THINGS."
|
|
||||||
(match things
|
|
||||||
((one)
|
|
||||||
;; Only one thing; return it.
|
|
||||||
(with-monad %store-monad (return one)))
|
|
||||||
(_
|
|
||||||
(gexp->derivation name
|
|
||||||
#~(begin
|
|
||||||
(use-modules (guix build union))
|
|
||||||
(union-build #$output '#$things))
|
|
||||||
#:modules '((guix build union))
|
|
||||||
#:local-build? #t))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Services.
|
;;; Services.
|
||||||
|
@ -244,18 +207,7 @@ as 'needed-for-boot'."
|
||||||
(string->symbol (mapped-device-target md))))
|
(string->symbol (mapped-device-target md))))
|
||||||
(device-mappings fs))))
|
(device-mappings fs))))
|
||||||
|
|
||||||
(map (lambda (fs)
|
(map file-system-service file-systems))
|
||||||
(match fs
|
|
||||||
(($ <file-system> device title target type flags opts
|
|
||||||
#f check? create?)
|
|
||||||
(file-system-service device target type
|
|
||||||
#:title title
|
|
||||||
#:requirements (requirements fs)
|
|
||||||
#:check? check?
|
|
||||||
#:create-mount-point? create?
|
|
||||||
#:options opts
|
|
||||||
#:flags flags))))
|
|
||||||
file-systems))
|
|
||||||
|
|
||||||
(define (mapped-device-user device file-systems)
|
(define (mapped-device-user device file-systems)
|
||||||
"Return a file system among FILE-SYSTEMS that uses DEVICE, or #f."
|
"Return a file system among FILE-SYSTEMS that uses DEVICE, or #f."
|
||||||
|
@ -302,10 +254,11 @@ from the initrd."
|
||||||
"Return the list of swap services for OS."
|
"Return the list of swap services for OS."
|
||||||
(map swap-service (operating-system-swap-devices os)))
|
(map swap-service (operating-system-swap-devices os)))
|
||||||
|
|
||||||
(define (essential-services os)
|
(define* (essential-services os #:key container?)
|
||||||
"Return the list of essential services for OS. These are special services
|
"Return the list of essential services for OS. These are special services
|
||||||
that implement part of what's declared in OS are responsible for low-level
|
that implement part of what's declared in OS are responsible for low-level
|
||||||
bookkeeping."
|
bookkeeping. CONTAINER? determines whether to return the list of services for
|
||||||
|
a container or that of a \"bare metal\" system."
|
||||||
(define known-fs
|
(define known-fs
|
||||||
(map file-system-mount-point (operating-system-file-systems os)))
|
(map file-system-mount-point (operating-system-file-systems os)))
|
||||||
|
|
||||||
|
@ -315,17 +268,36 @@ bookkeeping."
|
||||||
(unmount (user-unmount-service known-fs))
|
(unmount (user-unmount-service known-fs))
|
||||||
(swaps (swap-services os))
|
(swaps (swap-services os))
|
||||||
(procs (user-processes-service
|
(procs (user-processes-service
|
||||||
(map (compose first service-provision)
|
(map service-parameters other-fs)))
|
||||||
other-fs)))
|
|
||||||
(host-name (host-name-service (operating-system-host-name os))))
|
(host-name (host-name-service (operating-system-host-name os))))
|
||||||
(cons* host-name procs root-fs unmount
|
(cons* %boot-service
|
||||||
(append other-fs mappings swaps))))
|
|
||||||
|
|
||||||
(define (operating-system-services os)
|
;; %DMD-ROOT-SERVICE must come first so that the gexp that execs
|
||||||
|
;; dmd comes last in the boot script (XXX).
|
||||||
|
%dmd-root-service %activation-service
|
||||||
|
|
||||||
|
(pam-root-service (operating-system-pam-services os))
|
||||||
|
(account-service (append (operating-system-accounts os)
|
||||||
|
(operating-system-groups os))
|
||||||
|
(operating-system-skeletons os))
|
||||||
|
(operating-system-etc-service os)
|
||||||
|
host-name procs root-fs unmount
|
||||||
|
(service setuid-program-service-type
|
||||||
|
(operating-system-setuid-programs os))
|
||||||
|
(append other-fs mappings swaps
|
||||||
|
|
||||||
|
;; Add the firmware service, unless we are building for a
|
||||||
|
;; container.
|
||||||
|
(if container?
|
||||||
|
'()
|
||||||
|
(list (service firmware-service-type
|
||||||
|
(operating-system-firmware os))))))))
|
||||||
|
|
||||||
|
(define* (operating-system-services os #:key container?)
|
||||||
"Return all the services of OS, including \"internal\" services that do not
|
"Return all the services of OS, including \"internal\" services that do not
|
||||||
explicitly appear in OS."
|
explicitly appear in OS."
|
||||||
(append (operating-system-user-services os)
|
(append (operating-system-user-services os)
|
||||||
(essential-services os)))
|
(essential-services os #:container? container?)))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
|
@ -388,28 +360,27 @@ This is the GNU system. Welcome.\n")
|
||||||
(define (emacs-site-file)
|
(define (emacs-site-file)
|
||||||
"Return the Emacs 'site-start.el' file. That file contains the necessary
|
"Return the Emacs 'site-start.el' file. That file contains the necessary
|
||||||
settings for 'guix.el' to work out-of-the-box."
|
settings for 'guix.el' to work out-of-the-box."
|
||||||
(gexp->file "site-start.el"
|
(scheme-file "site-start.el"
|
||||||
#~(progn
|
#~(progn
|
||||||
;; Add the "normal" elisp directory to the search path;
|
;; Add the "normal" elisp directory to the search path;
|
||||||
;; guix.el may be there.
|
;; guix.el may be there.
|
||||||
(add-to-list
|
(add-to-list
|
||||||
'load-path
|
'load-path
|
||||||
"/run/current-system/profile/share/emacs/site-lisp")
|
"/run/current-system/profile/share/emacs/site-lisp")
|
||||||
|
|
||||||
;; Attempt to load guix.el.
|
;; Attempt to load guix.el.
|
||||||
(require 'guix-init nil t)
|
(require 'guix-init nil t)
|
||||||
|
|
||||||
;; Attempt to load geiser.
|
;; Attempt to load geiser.
|
||||||
(require 'geiser-install nil t))))
|
(require 'geiser-install nil t))))
|
||||||
|
|
||||||
(define (emacs-site-directory)
|
(define (emacs-site-directory)
|
||||||
"Return the Emacs site directory, aka. /etc/emacs."
|
"Return the Emacs site directory, aka. /etc/emacs."
|
||||||
(mlet %store-monad ((file (emacs-site-file)))
|
(computed-file "emacs"
|
||||||
(gexp->derivation "emacs"
|
#~(begin
|
||||||
#~(begin
|
(mkdir #$output)
|
||||||
(mkdir #$output)
|
(chdir #$output)
|
||||||
(chdir #$output)
|
(symlink #$(emacs-site-file) "site-start.el"))))
|
||||||
(symlink #$file "site-start.el")))))
|
|
||||||
|
|
||||||
(define (user-shells os)
|
(define (user-shells os)
|
||||||
"Return the list of all the shells used by the accounts of OS. These may be
|
"Return the list of all the shells used by the accounts of OS. These may be
|
||||||
|
@ -417,49 +388,43 @@ gexps or strings."
|
||||||
(map user-account-shell (operating-system-accounts os)))
|
(map user-account-shell (operating-system-accounts os)))
|
||||||
|
|
||||||
(define (shells-file shells)
|
(define (shells-file shells)
|
||||||
"Return a derivation that builds a shell list for use as /etc/shells based
|
"Return a file-like object that builds a shell list for use as /etc/shells
|
||||||
on SHELLS. /etc/shells is used by xterm, polkit, and other programs."
|
based on SHELLS. /etc/shells is used by xterm, polkit, and other programs."
|
||||||
(gexp->derivation "shells"
|
(computed-file "shells"
|
||||||
#~(begin
|
#~(begin
|
||||||
(use-modules (srfi srfi-1))
|
(use-modules (srfi srfi-1))
|
||||||
|
|
||||||
(define shells
|
(define shells
|
||||||
(delete-duplicates (list #$@shells)))
|
(delete-duplicates (list #$@shells)))
|
||||||
|
|
||||||
(call-with-output-file #$output
|
(call-with-output-file #$output
|
||||||
(lambda (port)
|
(lambda (port)
|
||||||
(display "\
|
(display "\
|
||||||
/bin/sh
|
/bin/sh
|
||||||
/run/current-system/profile/bin/sh
|
/run/current-system/profile/bin/sh
|
||||||
/run/current-system/profile/bin/bash\n" port)
|
/run/current-system/profile/bin/bash\n" port)
|
||||||
(for-each (lambda (shell)
|
(for-each (lambda (shell)
|
||||||
(display shell port)
|
(display shell port)
|
||||||
(newline port))
|
(newline port))
|
||||||
shells))))))
|
shells))))))
|
||||||
|
|
||||||
(define* (etc-directory #:key
|
(define* (operating-system-etc-service os)
|
||||||
(locale "C") (timezone "Europe/Paris")
|
"Return a <service> that builds containing the static part of the /etc
|
||||||
(issue "Hello!\n")
|
directory."
|
||||||
(skeletons '())
|
(let ((login.defs (plain-file "login.defs" "# Empty for now.\n"))
|
||||||
(pam-services '())
|
|
||||||
(profile "/run/current-system/profile")
|
|
||||||
hosts-file nss (shells '())
|
|
||||||
(sudoers-file (plain-file "sudoers" "")))
|
|
||||||
"Return a derivation that builds the static part of the /etc directory."
|
|
||||||
(mlet* %store-monad
|
|
||||||
((pam.d -> (pam-services->directory pam-services))
|
|
||||||
(login.defs (text-file "login.defs" "# Empty for now.\n"))
|
|
||||||
(shells (shells-file shells))
|
|
||||||
(emacs (emacs-site-directory))
|
|
||||||
(issue (text-file "issue" issue))
|
|
||||||
(nsswitch (text-file "nsswitch.conf"
|
|
||||||
(name-service-switch->string nss)))
|
|
||||||
|
|
||||||
;; Startup file for POSIX-compliant login shells, which set system-wide
|
(shells (shells-file (user-shells os)))
|
||||||
;; environment variables.
|
(emacs (emacs-site-directory))
|
||||||
(profile (text-file* "profile" "\
|
(issue (plain-file "issue" (operating-system-issue os)))
|
||||||
export LANG=\"" locale "\"
|
(nsswitch (plain-file "nsswitch.conf"
|
||||||
export TZ=\"" timezone "\"
|
(name-service-switch->string
|
||||||
|
(operating-system-name-service-switch os))))
|
||||||
|
|
||||||
|
;; Startup file for POSIX-compliant login shells, which set system-wide
|
||||||
|
;; environment variables.
|
||||||
|
(profile (mixed-text-file "profile" "\
|
||||||
|
export LANG=\"" (operating-system-locale os) "\"
|
||||||
|
export TZ=\"" (operating-system-timezone os) "\"
|
||||||
export TZDIR=\"" tzdata "/share/zoneinfo\"
|
export TZDIR=\"" tzdata "/share/zoneinfo\"
|
||||||
|
|
||||||
# Tell 'modprobe' & co. where to look for modules.
|
# Tell 'modprobe' & co. where to look for modules.
|
||||||
|
@ -516,7 +481,7 @@ then
|
||||||
fi
|
fi
|
||||||
"))
|
"))
|
||||||
|
|
||||||
(bashrc (text-file "bashrc" "\
|
(bashrc (plain-file "bashrc" "\
|
||||||
# Bash-specific initialization.
|
# Bash-specific initialization.
|
||||||
|
|
||||||
# The 'bash-completion' package.
|
# The 'bash-completion' package.
|
||||||
|
@ -526,25 +491,23 @@ then
|
||||||
# completion loader that searches its own completion files as well
|
# completion loader that searches its own completion files as well
|
||||||
# as those in ~/.guix-profile and /run/current-system/profile.
|
# as those in ~/.guix-profile and /run/current-system/profile.
|
||||||
source /run/current-system/profile/etc/profile.d/bash_completion.sh
|
source /run/current-system/profile/etc/profile.d/bash_completion.sh
|
||||||
fi\n"))
|
fi\n")))
|
||||||
(skel -> (skeleton-directory skeletons)))
|
(etc-service
|
||||||
(file-union "etc"
|
`(("services" ,#~(string-append #$net-base "/etc/services"))
|
||||||
`(("services" ,#~(string-append #$net-base "/etc/services"))
|
("protocols" ,#~(string-append #$net-base "/etc/protocols"))
|
||||||
("protocols" ,#~(string-append #$net-base "/etc/protocols"))
|
("rpc" ,#~(string-append #$net-base "/etc/rpc"))
|
||||||
("rpc" ,#~(string-append #$net-base "/etc/rpc"))
|
("emacs" ,#~#$emacs)
|
||||||
("emacs" ,#~#$emacs)
|
("login.defs" ,#~#$login.defs)
|
||||||
("pam.d" ,#~#$pam.d)
|
("issue" ,#~#$issue)
|
||||||
("login.defs" ,#~#$login.defs)
|
("nsswitch.conf" ,#~#$nsswitch)
|
||||||
("issue" ,#~#$issue)
|
("shells" ,#~#$shells)
|
||||||
("nsswitch.conf" ,#~#$nsswitch)
|
("profile" ,#~#$profile)
|
||||||
("skel" ,#~#$skel)
|
("bashrc" ,#~#$bashrc)
|
||||||
("shells" ,#~#$shells)
|
("hosts" ,#~#$(or (operating-system-hosts-file os)
|
||||||
("profile" ,#~#$profile)
|
(default-/etc/hosts (operating-system-host-name os))))
|
||||||
("bashrc" ,#~#$bashrc)
|
("localtime" ,#~(string-append #$tzdata "/share/zoneinfo/"
|
||||||
("hosts" ,#~#$hosts-file)
|
#$(operating-system-timezone os)))
|
||||||
("localtime" ,#~(string-append #$tzdata "/share/zoneinfo/"
|
("sudoers" ,(operating-system-sudoers-file os))))))
|
||||||
#$timezone))
|
|
||||||
("sudoers" ,sudoers-file)))))
|
|
||||||
|
|
||||||
(define (operating-system-profile os)
|
(define (operating-system-profile os)
|
||||||
"Return a derivation that builds the system profile of OS."
|
"Return a derivation that builds the system profile of OS."
|
||||||
|
@ -561,18 +524,14 @@ fi\n"))
|
||||||
(home-directory "/root")))
|
(home-directory "/root")))
|
||||||
|
|
||||||
(define (operating-system-accounts os)
|
(define (operating-system-accounts os)
|
||||||
"Return the user accounts for OS, including an obligatory 'root' account."
|
"Return the user accounts for OS, including an obligatory 'root' account,
|
||||||
(define users
|
and excluding accounts requested by services."
|
||||||
;; Make sure there's a root account.
|
;; Make sure there's a root account.
|
||||||
(if (find (lambda (user)
|
(if (find (lambda (user)
|
||||||
(and=> (user-account-uid user) zero?))
|
(and=> (user-account-uid user) zero?))
|
||||||
(operating-system-users os))
|
(operating-system-users os))
|
||||||
(operating-system-users os)
|
(operating-system-users os)
|
||||||
(cons %root-account (operating-system-users os))))
|
(cons %root-account (operating-system-users os))))
|
||||||
|
|
||||||
(append users
|
|
||||||
(append-map service-user-accounts
|
|
||||||
(operating-system-services os))))
|
|
||||||
|
|
||||||
(define (maybe-string->file file-name thing)
|
(define (maybe-string->file file-name thing)
|
||||||
"If THING is a string, return a <plain-file> with THING as its content.
|
"If THING is a string, return a <plain-file> with THING as its content.
|
||||||
|
@ -607,31 +566,9 @@ use 'plain-file' instead~%")
|
||||||
|
|
||||||
(define (operating-system-etc-directory os)
|
(define (operating-system-etc-directory os)
|
||||||
"Return that static part of the /etc directory of OS."
|
"Return that static part of the /etc directory of OS."
|
||||||
(mlet* %store-monad
|
(etc-directory
|
||||||
((services -> (operating-system-services os))
|
(fold-services (operating-system-services os)
|
||||||
(pam-services ->
|
#:target-type etc-service-type)))
|
||||||
;; Services known to PAM.
|
|
||||||
(append (operating-system-pam-services os)
|
|
||||||
(append-map service-pam-services services)))
|
|
||||||
(profile-drv (operating-system-profile os))
|
|
||||||
(skeletons (operating-system-skeletons os))
|
|
||||||
(/etc/hosts (maybe-file->monadic
|
|
||||||
"hosts"
|
|
||||||
(or (operating-system-hosts-file os)
|
|
||||||
(default-/etc/hosts (operating-system-host-name os)))))
|
|
||||||
(shells -> (user-shells os)))
|
|
||||||
(etc-directory #:pam-services pam-services
|
|
||||||
#:skeletons skeletons
|
|
||||||
#:issue (operating-system-issue os)
|
|
||||||
#:locale (operating-system-locale os)
|
|
||||||
#:nss (operating-system-name-service-switch os)
|
|
||||||
#:timezone (operating-system-timezone os)
|
|
||||||
#:hosts-file /etc/hosts
|
|
||||||
#:shells shells
|
|
||||||
#:sudoers-file (maybe-string->file
|
|
||||||
"sudoers"
|
|
||||||
(operating-system-sudoers-file os))
|
|
||||||
#:profile profile-drv)))
|
|
||||||
|
|
||||||
(define %setuid-programs
|
(define %setuid-programs
|
||||||
;; Default set of setuid-root programs.
|
;; Default set of setuid-root programs.
|
||||||
|
@ -652,176 +589,23 @@ use 'plain-file' instead~%")
|
||||||
root ALL=(ALL) ALL
|
root ALL=(ALL) ALL
|
||||||
%wheel ALL=(ALL) ALL\n"))
|
%wheel ALL=(ALL) ALL\n"))
|
||||||
|
|
||||||
(define (user-group->gexp group)
|
|
||||||
"Turn GROUP, a <user-group> object, into a list-valued gexp suitable for
|
|
||||||
'active-groups'."
|
|
||||||
#~(list #$(user-group-name group)
|
|
||||||
#$(user-group-password group)
|
|
||||||
#$(user-group-id group)
|
|
||||||
#$(user-group-system? group)))
|
|
||||||
|
|
||||||
(define (user-account->gexp account)
|
|
||||||
"Turn ACCOUNT, a <user-account> object, into a list-valued gexp suitable for
|
|
||||||
'activate-users'."
|
|
||||||
#~`(#$(user-account-name account)
|
|
||||||
#$(user-account-uid account)
|
|
||||||
#$(user-account-group account)
|
|
||||||
#$(user-account-supplementary-groups account)
|
|
||||||
#$(user-account-comment account)
|
|
||||||
#$(user-account-home-directory account)
|
|
||||||
,#$(user-account-shell account) ; this one is a gexp
|
|
||||||
#$(user-account-password account)
|
|
||||||
#$(user-account-system? account)))
|
|
||||||
|
|
||||||
(define (modprobe-wrapper)
|
|
||||||
"Return a wrapper for the 'modprobe' command that knows where modules live.
|
|
||||||
|
|
||||||
This wrapper is typically invoked by the Linux kernel ('call_modprobe', in
|
|
||||||
kernel/kmod.c), a situation where the 'LINUX_MODULE_DIRECTORY' environment
|
|
||||||
variable is not set---hence the need for this wrapper."
|
|
||||||
(let ((modprobe "/run/current-system/profile/bin/modprobe"))
|
|
||||||
(gexp->script "modprobe"
|
|
||||||
#~(begin
|
|
||||||
(setenv "LINUX_MODULE_DIRECTORY"
|
|
||||||
"/run/booted-system/kernel/lib/modules")
|
|
||||||
(apply execl #$modprobe
|
|
||||||
(cons #$modprobe (cdr (command-line))))))))
|
|
||||||
|
|
||||||
(define* (operating-system-activation-script os #:key container?)
|
(define* (operating-system-activation-script os #:key container?)
|
||||||
"Return the activation script for OS---i.e., the code that \"activates\" the
|
"Return the activation script for OS---i.e., the code that \"activates\" the
|
||||||
stateful part of OS, including user accounts and groups, special directories,
|
stateful part of OS, including user accounts and groups, special directories,
|
||||||
etc."
|
etc."
|
||||||
(define %modules
|
(let* ((services (operating-system-services os #:container? container?))
|
||||||
'((gnu build activation)
|
(activation (fold-services services
|
||||||
(gnu build linux-boot)
|
#:target-type activation-service-type)))
|
||||||
(gnu build linux-modules)
|
(activation-service->script activation)))
|
||||||
(gnu build file-systems)
|
|
||||||
(guix build utils)
|
|
||||||
(guix build syscalls)
|
|
||||||
(guix elf)))
|
|
||||||
|
|
||||||
(define (service-activations services)
|
|
||||||
;; Return the activation scripts for SERVICES.
|
|
||||||
(let ((gexps (filter-map service-activate services)))
|
|
||||||
(sequence %store-monad (map (cut gexp->file "activate-service.scm" <>)
|
|
||||||
gexps))))
|
|
||||||
|
|
||||||
(mlet* %store-monad ((services -> (operating-system-services os))
|
|
||||||
(actions (service-activations services))
|
|
||||||
(etc (operating-system-etc-directory os))
|
|
||||||
(modules (imported-modules %modules))
|
|
||||||
(compiled (compiled-modules %modules))
|
|
||||||
(modprobe (modprobe-wrapper))
|
|
||||||
(firmware (directory-union
|
|
||||||
"firmware" (operating-system-firmware os)))
|
|
||||||
(accounts -> (operating-system-accounts os)))
|
|
||||||
(define setuid-progs
|
|
||||||
(operating-system-setuid-programs os))
|
|
||||||
|
|
||||||
(define user-specs
|
|
||||||
(map user-account->gexp accounts))
|
|
||||||
|
|
||||||
(define groups
|
|
||||||
(append (operating-system-groups os)
|
|
||||||
(append-map service-user-groups services)))
|
|
||||||
|
|
||||||
(define group-specs
|
|
||||||
(map user-group->gexp groups))
|
|
||||||
|
|
||||||
(assert-valid-users/groups accounts groups)
|
|
||||||
|
|
||||||
(gexp->file "activate"
|
|
||||||
#~(begin
|
|
||||||
(eval-when (expand load eval)
|
|
||||||
;; Make sure 'use-modules' below succeeds.
|
|
||||||
(set! %load-path (cons #$modules %load-path))
|
|
||||||
(set! %load-compiled-path
|
|
||||||
(cons #$compiled %load-compiled-path)))
|
|
||||||
|
|
||||||
(use-modules (gnu build activation))
|
|
||||||
|
|
||||||
;; Make sure /bin/sh is valid and current.
|
|
||||||
(activate-/bin/sh
|
|
||||||
(string-append #$(canonical-package bash)
|
|
||||||
"/bin/sh"))
|
|
||||||
|
|
||||||
;; Populate /etc.
|
|
||||||
(activate-etc #$etc)
|
|
||||||
|
|
||||||
;; Add users and user groups.
|
|
||||||
(setenv "PATH"
|
|
||||||
(string-append #$(@ (gnu packages admin) shadow)
|
|
||||||
"/sbin"))
|
|
||||||
(activate-users+groups (list #$@user-specs)
|
|
||||||
(list #$@group-specs))
|
|
||||||
|
|
||||||
;; Activate setuid programs.
|
|
||||||
(activate-setuid-programs (list #$@setuid-progs))
|
|
||||||
|
|
||||||
;; Tell the kernel to use our 'modprobe' command.
|
|
||||||
(activate-modprobe #$modprobe)
|
|
||||||
|
|
||||||
;; Tell the kernel where firmware is, unless we are
|
|
||||||
;; activating a container.
|
|
||||||
#$@(if container?
|
|
||||||
#~()
|
|
||||||
;; Tell the kernel where firmware is.
|
|
||||||
#~((activate-firmware
|
|
||||||
(string-append #$firmware "/lib/firmware"))
|
|
||||||
;; Let users debug their own processes!
|
|
||||||
(activate-ptrace-attach)))
|
|
||||||
|
|
||||||
;; Run the services' activation snippets.
|
|
||||||
;; TODO: Use 'load-compiled'.
|
|
||||||
(for-each primitive-load '#$actions)
|
|
||||||
|
|
||||||
;; Set up /run/current-system.
|
|
||||||
(activate-current-system)))))
|
|
||||||
|
|
||||||
(define* (operating-system-boot-script os #:key container?)
|
(define* (operating-system-boot-script os #:key container?)
|
||||||
"Return the boot script for OS---i.e., the code started by the initrd once
|
"Return the boot script for OS---i.e., the code started by the initrd once
|
||||||
we're running in the final root. When CONTAINER? is true, skip all
|
we're running in the final root. When CONTAINER? is true, skip all
|
||||||
hardware-related operations as necessary when booting a Linux container."
|
hardware-related operations as necessary when booting a Linux container."
|
||||||
(mlet* %store-monad ((services -> (operating-system-services os))
|
(let* ((services (operating-system-services os #:container? container?))
|
||||||
(activate (operating-system-activation-script os))
|
(boot (fold-services services)))
|
||||||
(dmd-conf (dmd-configuration-file services)))
|
;; BOOT is the script as a monadic value.
|
||||||
(gexp->file "boot"
|
(service-parameters boot)))
|
||||||
#~(begin
|
|
||||||
(use-modules (guix build utils))
|
|
||||||
|
|
||||||
;; Clean out /tmp and /var/run.
|
|
||||||
;;
|
|
||||||
;; XXX This needs to happen before service activations, so
|
|
||||||
;; it has to be here, but this also implicitly assumes
|
|
||||||
;; that /tmp and /var/run are on the root partition.
|
|
||||||
(false-if-exception (delete-file-recursively "/tmp"))
|
|
||||||
(false-if-exception (delete-file-recursively "/var/run"))
|
|
||||||
(false-if-exception (mkdir "/tmp"))
|
|
||||||
(false-if-exception (chmod "/tmp" #o1777))
|
|
||||||
(false-if-exception (mkdir "/var/run"))
|
|
||||||
(false-if-exception (chmod "/var/run" #o755))
|
|
||||||
|
|
||||||
;; Activate the system.
|
|
||||||
;; TODO: Use 'load-compiled'.
|
|
||||||
(primitive-load #$activate)
|
|
||||||
|
|
||||||
;; Keep track of the booted system.
|
|
||||||
(false-if-exception (delete-file "/run/booted-system"))
|
|
||||||
(symlink (readlink "/run/current-system")
|
|
||||||
"/run/booted-system")
|
|
||||||
|
|
||||||
;; Close any remaining open file descriptors to be on the
|
|
||||||
;; safe side. This must be the very last thing we do,
|
|
||||||
;; because Guile has internal FDs such as 'sleep_pipe'
|
|
||||||
;; that need to be alive.
|
|
||||||
(let loop ((fd 3))
|
|
||||||
(when (< fd 1024)
|
|
||||||
(false-if-exception (close-fdes fd))
|
|
||||||
(loop (+ 1 fd))))
|
|
||||||
|
|
||||||
;; Start dmd.
|
|
||||||
(execl (string-append #$dmd "/bin/dmd")
|
|
||||||
"dmd" "--config" #$dmd-conf)))))
|
|
||||||
|
|
||||||
(define (operating-system-root-file-system os)
|
(define (operating-system-root-file-system os)
|
||||||
"Return the root file system of OS."
|
"Return the root file system of OS."
|
||||||
|
@ -908,19 +692,20 @@ this file is the reconstruction of GRUB menu entries for old configurations."
|
||||||
"Return a derivation that builds OS."
|
"Return a derivation that builds OS."
|
||||||
(mlet* %store-monad
|
(mlet* %store-monad
|
||||||
((profile (operating-system-profile os))
|
((profile (operating-system-profile os))
|
||||||
(etc (operating-system-etc-directory os))
|
(etc -> (operating-system-etc-directory os))
|
||||||
(boot (operating-system-boot-script os))
|
(boot (operating-system-boot-script os))
|
||||||
(kernel -> (operating-system-kernel os))
|
(kernel -> (operating-system-kernel os))
|
||||||
(initrd (operating-system-initrd-file os))
|
(initrd (operating-system-initrd-file os))
|
||||||
(locale (operating-system-locale-directory os))
|
(locale (operating-system-locale-directory os))
|
||||||
(params (operating-system-parameters-file os)))
|
(params (operating-system-parameters-file os)))
|
||||||
(file-union "system"
|
(lower-object
|
||||||
`(("boot" ,#~#$boot)
|
(file-union "system"
|
||||||
("kernel" ,#~#$kernel)
|
`(("boot" ,#~#$boot)
|
||||||
("parameters" ,#~#$params)
|
("kernel" ,#~#$kernel)
|
||||||
("initrd" ,initrd)
|
("parameters" ,#~#$params)
|
||||||
("profile" ,#~#$profile)
|
("initrd" ,initrd)
|
||||||
("locale" ,#~#$locale) ;used by libc
|
("profile" ,#~#$profile)
|
||||||
("etc" ,#~#$etc)))))
|
("locale" ,#~#$locale) ;used by libc
|
||||||
|
("etc" ,#~#$etc))))))
|
||||||
|
|
||||||
;;; system.scm ends here
|
;;; system.scm ends here
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#:use-module (guix monads)
|
#:use-module (guix monads)
|
||||||
#:use-module ((guix store) #:select (%store-prefix))
|
#:use-module ((guix store) #:select (%store-prefix))
|
||||||
#:use-module (guix profiles)
|
#:use-module (guix profiles)
|
||||||
|
#:use-module (gnu services dmd)
|
||||||
#:use-module (gnu packages admin)
|
#:use-module (gnu packages admin)
|
||||||
#:use-module (gnu packages bash)
|
#:use-module (gnu packages bash)
|
||||||
#:use-module (gnu packages linux)
|
#:use-module (gnu packages linux)
|
||||||
|
@ -159,68 +160,74 @@ current store is on a RAM disk."
|
||||||
(mount "/.rw-store" #$(%store-prefix) "" MS_MOVE)
|
(mount "/.rw-store" #$(%store-prefix) "" MS_MOVE)
|
||||||
(rmdir "/.rw-store"))))))
|
(rmdir "/.rw-store"))))))
|
||||||
|
|
||||||
|
(define cow-store-service-type
|
||||||
|
(dmd-service-type
|
||||||
|
(lambda _
|
||||||
|
(dmd-service
|
||||||
|
(requirement '(root-file-system user-processes))
|
||||||
|
(provision '(cow-store))
|
||||||
|
(documentation
|
||||||
|
"Make the store copy-on-write, with writes going to \
|
||||||
|
the given target.")
|
||||||
|
|
||||||
|
;; This is meant to be explicitly started by the user.
|
||||||
|
(auto-start? #f)
|
||||||
|
|
||||||
|
(start #~(case-lambda
|
||||||
|
((target)
|
||||||
|
#$(make-cow-store #~target)
|
||||||
|
target)
|
||||||
|
(else
|
||||||
|
;; Do nothing, and mark the service as stopped.
|
||||||
|
#f)))
|
||||||
|
(stop #~(lambda (target)
|
||||||
|
;; Delete the temporary directory, but leave everything
|
||||||
|
;; mounted as there may still be processes using it since
|
||||||
|
;; 'user-processes' doesn't depend on us. The 'user-unmount'
|
||||||
|
;; service will unmount TARGET eventually.
|
||||||
|
(delete-file-recursively
|
||||||
|
(string-append target #$%backing-directory))))))))
|
||||||
|
|
||||||
(define (cow-store-service)
|
(define (cow-store-service)
|
||||||
"Return a service that makes the store copy-on-write, such that writes go to
|
"Return a service that makes the store copy-on-write, such that writes go to
|
||||||
the user's target storage device rather than on the RAM disk."
|
the user's target storage device rather than on the RAM disk."
|
||||||
;; See <http://bugs.gnu.org/18061> for the initial report.
|
;; See <http://bugs.gnu.org/18061> for the initial report.
|
||||||
(service
|
(service cow-store-service-type 'mooooh!))
|
||||||
(requirement '(root-file-system user-processes))
|
|
||||||
(provision '(cow-store))
|
|
||||||
(documentation
|
|
||||||
"Make the store copy-on-write, with writes going to \
|
|
||||||
the given target.")
|
|
||||||
|
|
||||||
;; This is meant to be explicitly started by the user.
|
|
||||||
(auto-start? #f)
|
|
||||||
|
|
||||||
(start #~(case-lambda
|
(define (/etc/configuration-files _)
|
||||||
((target)
|
"Return a list of tuples representing configuration templates to add to
|
||||||
#$(make-cow-store #~target)
|
/etc."
|
||||||
target)
|
(define (file f)
|
||||||
(else
|
(local-file (search-path %load-path
|
||||||
;; Do nothing, and mark the service as stopped.
|
(string-append "gnu/system/examples/" f))))
|
||||||
#f)))
|
|
||||||
(stop #~(lambda (target)
|
|
||||||
;; Delete the temporary directory, but leave everything
|
|
||||||
;; mounted as there may still be processes using it
|
|
||||||
;; since 'user-processes' doesn't depend on us. The
|
|
||||||
;; 'user-unmount' service will unmount TARGET
|
|
||||||
;; eventually.
|
|
||||||
(delete-file-recursively
|
|
||||||
(string-append target #$%backing-directory))))))
|
|
||||||
|
|
||||||
(define (configuration-template-service)
|
(define directory
|
||||||
"Return a dummy service whose purpose is to install an operating system
|
(computed-file "configuration-templates"
|
||||||
configuration template file in the installation system."
|
#~(begin
|
||||||
|
(mkdir #$output)
|
||||||
|
(for-each (lambda (file target)
|
||||||
|
(copy-file file
|
||||||
|
(string-append #$output "/"
|
||||||
|
target)))
|
||||||
|
'(#$(file "bare-bones.tmpl")
|
||||||
|
#$(file "desktop.tmpl"))
|
||||||
|
'("bare-bones.scm"
|
||||||
|
"desktop.scm"))
|
||||||
|
#t)
|
||||||
|
#:modules '((guix build utils))))
|
||||||
|
|
||||||
(define search
|
`(("configuration" ,directory)))
|
||||||
(cut search-path %load-path <>))
|
|
||||||
(define templates
|
|
||||||
(map (match-lambda
|
|
||||||
((file '-> target)
|
|
||||||
(list (local-file (search file))
|
|
||||||
(string-append "/etc/configuration/" target))))
|
|
||||||
'(("gnu/system/examples/bare-bones.tmpl" -> "bare-bones.scm")
|
|
||||||
("gnu/system/examples/desktop.tmpl" -> "desktop.scm"))))
|
|
||||||
|
|
||||||
(service
|
(define configuration-template-service-type
|
||||||
(requirement '(root-file-system))
|
(service-type (name 'configuration-template)
|
||||||
(provision '(os-config-template))
|
(extensions
|
||||||
(documentation
|
(list (service-extension etc-service-type
|
||||||
"This dummy service installs an OS configuration template.")
|
/etc/configuration-files)))))
|
||||||
(start #~(const #t))
|
|
||||||
(stop #~(const #f))
|
(define %configuration-template-service
|
||||||
(activate
|
(service configuration-template-service-type #t))
|
||||||
#~(begin
|
|
||||||
(use-modules (ice-9 match)
|
|
||||||
(guix build utils))
|
|
||||||
|
|
||||||
(mkdir-p "/etc/configuration")
|
|
||||||
(for-each (match-lambda
|
|
||||||
((file target)
|
|
||||||
(unless (file-exists? target)
|
|
||||||
(copy-file file target))))
|
|
||||||
'#$templates)))))
|
|
||||||
|
|
||||||
(define %nscd-minimal-caches
|
(define %nscd-minimal-caches
|
||||||
;; Minimal in-memory caching policy for nscd.
|
;; Minimal in-memory caching policy for nscd.
|
||||||
|
@ -262,7 +269,7 @@ You have been warned. Thanks for being so brave.
|
||||||
(login-program (log-to-info))))
|
(login-program (log-to-info))))
|
||||||
|
|
||||||
;; Documentation add-on.
|
;; Documentation add-on.
|
||||||
(configuration-template-service)
|
%configuration-template-service
|
||||||
|
|
||||||
;; A bunch of 'root' ttys.
|
;; A bunch of 'root' ttys.
|
||||||
(normal-tty "tty3")
|
(normal-tty "tty3")
|
||||||
|
@ -276,7 +283,7 @@ You have been warned. Thanks for being so brave.
|
||||||
;; The build daemon. Register the hydra.gnu.org key as trusted.
|
;; The build daemon. Register the hydra.gnu.org key as trusted.
|
||||||
;; This allows the installation process to use substitutes by
|
;; This allows the installation process to use substitutes by
|
||||||
;; default.
|
;; default.
|
||||||
(guix-service #:authorize-hydra-key? #t)
|
(guix-service (guix-configuration (authorize-key? #t)))
|
||||||
|
|
||||||
;; Start udev so that useful device nodes are available.
|
;; Start udev so that useful device nodes are available.
|
||||||
;; Use device-mapper rules for cryptsetup & co; enable the CRDA for
|
;; Use device-mapper rules for cryptsetup & co; enable the CRDA for
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#:use-module (guix records)
|
#:use-module (guix records)
|
||||||
#:use-module (guix derivations)
|
#:use-module (guix derivations)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (gnu services)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (srfi srfi-26)
|
#:use-module (srfi srfi-26)
|
||||||
|
@ -28,7 +29,10 @@
|
||||||
pam-entry
|
pam-entry
|
||||||
pam-services->directory
|
pam-services->directory
|
||||||
unix-pam-service
|
unix-pam-service
|
||||||
base-pam-services))
|
base-pam-services
|
||||||
|
|
||||||
|
pam-root-service-type
|
||||||
|
pam-root-service))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;;
|
;;;
|
||||||
|
@ -98,8 +102,8 @@ dumped in /etc/pam.d/NAME, where NAME is the name of SERVICE."
|
||||||
|
|
||||||
(mkdir #$output)
|
(mkdir #$output)
|
||||||
(for-each (match-lambda
|
(for-each (match-lambda
|
||||||
((name file)
|
((name file)
|
||||||
(symlink file (string-append #$output "/" name))))
|
(symlink file (string-append #$output "/" name))))
|
||||||
|
|
||||||
;; Since <pam-service> objects cannot be compared with
|
;; Since <pam-service> objects cannot be compared with
|
||||||
;; 'equal?' since they contain gexps, which contain
|
;; 'equal?' since they contain gexps, which contain
|
||||||
|
@ -188,4 +192,24 @@ authenticate to run COMMAND."
|
||||||
'("useradd" "userdel" "usermod"
|
'("useradd" "userdel" "usermod"
|
||||||
"groupadd" "groupdel" "groupmod"))))
|
"groupadd" "groupdel" "groupmod"))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; PAM root service.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (/etc-entry services)
|
||||||
|
`(("pam.d" ,(pam-services->directory services))))
|
||||||
|
|
||||||
|
(define pam-root-service-type
|
||||||
|
(service-type (name 'pam)
|
||||||
|
(extensions (list (service-extension etc-service-type
|
||||||
|
/etc-entry)))
|
||||||
|
(compose concatenate)
|
||||||
|
(extend append)))
|
||||||
|
|
||||||
|
(define (pam-root-service base)
|
||||||
|
"The \"root\" PAM service, which collects <pam-service> instance and turns
|
||||||
|
them into a /etc/pam.d directory, including the <pam-service> listed in BASE."
|
||||||
|
(service pam-root-service-type base))
|
||||||
|
|
||||||
;;; linux.scm ends here
|
;;; linux.scm ends here
|
||||||
|
|
|
@ -22,12 +22,14 @@
|
||||||
#:use-module (guix store)
|
#:use-module (guix store)
|
||||||
#:use-module (guix sets)
|
#:use-module (guix sets)
|
||||||
#:use-module (guix ui)
|
#:use-module (guix ui)
|
||||||
|
#:use-module (gnu services)
|
||||||
#:use-module ((gnu system file-systems)
|
#:use-module ((gnu system file-systems)
|
||||||
#:select (%tty-gid))
|
#:select (%tty-gid))
|
||||||
#:use-module ((gnu packages admin)
|
#:use-module ((gnu packages admin)
|
||||||
#:select (shadow))
|
#:select (shadow))
|
||||||
#:use-module (gnu packages bash)
|
#:use-module (gnu packages bash)
|
||||||
#:use-module (gnu packages guile-wm)
|
#:use-module (gnu packages guile-wm)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (srfi srfi-26)
|
#:use-module (srfi srfi-26)
|
||||||
#:use-module (srfi srfi-34)
|
#:use-module (srfi srfi-34)
|
||||||
#:use-module (srfi srfi-35)
|
#:use-module (srfi srfi-35)
|
||||||
|
@ -54,7 +56,9 @@
|
||||||
skeleton-directory
|
skeleton-directory
|
||||||
%base-groups
|
%base-groups
|
||||||
%base-user-accounts
|
%base-user-accounts
|
||||||
assert-valid-users/groups))
|
|
||||||
|
account-service-type
|
||||||
|
account-service))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;;
|
;;;
|
||||||
|
@ -87,31 +91,32 @@
|
||||||
(system? user-group-system? ; Boolean
|
(system? user-group-system? ; Boolean
|
||||||
(default #f)))
|
(default #f)))
|
||||||
|
|
||||||
|
|
||||||
(define %base-groups
|
(define %base-groups
|
||||||
;; Default set of groups.
|
;; Default set of groups.
|
||||||
(let-syntax ((system-group (syntax-rules ()
|
(let-syntax ((system-group (syntax-rules ()
|
||||||
((_ args ...)
|
((_ args ...)
|
||||||
(user-group (system? #t) args ...)))))
|
(user-group (system? #t) args ...)))))
|
||||||
(list (system-group (name "root") (id 0))
|
(list (system-group (name "root") (id 0))
|
||||||
(system-group (name "wheel")) ; root-like users
|
(system-group (name "wheel")) ; root-like users
|
||||||
(system-group (name "users")) ; normal users
|
(system-group (name "users")) ; normal users
|
||||||
(system-group (name "nogroup")) ; for daemons etc.
|
(system-group (name "nogroup")) ; for daemons etc.
|
||||||
|
|
||||||
;; The following groups are conventionally used by things like udev to
|
;; The following groups are conventionally used by things like udev to
|
||||||
;; control access to hardware devices.
|
;; control access to hardware devices.
|
||||||
(system-group (name "tty") (id %tty-gid))
|
(system-group (name "tty") (id %tty-gid))
|
||||||
(system-group (name "dialout"))
|
(system-group (name "dialout"))
|
||||||
(system-group (name "kmem"))
|
(system-group (name "kmem"))
|
||||||
(system-group (name "input")) ; input devices, from udev
|
(system-group (name "input")) ; input devices, from udev
|
||||||
(system-group (name "video"))
|
(system-group (name "video"))
|
||||||
(system-group (name "audio"))
|
(system-group (name "audio"))
|
||||||
(system-group (name "netdev")) ; used in avahi-dbus.conf
|
(system-group (name "netdev")) ; used in avahi-dbus.conf
|
||||||
(system-group (name "lp"))
|
(system-group (name "lp"))
|
||||||
(system-group (name "disk"))
|
(system-group (name "disk"))
|
||||||
(system-group (name "floppy"))
|
(system-group (name "floppy"))
|
||||||
(system-group (name "cdrom"))
|
(system-group (name "cdrom"))
|
||||||
(system-group (name "tape"))
|
(system-group (name "tape"))
|
||||||
(system-group (name "kvm"))))) ; for /dev/kvm
|
(system-group (name "kvm"))))) ; for /dev/kvm
|
||||||
|
|
||||||
(define %base-user-accounts
|
(define %base-user-accounts
|
||||||
;; List of standard user accounts. Note that "root" is a special case, so
|
;; List of standard user accounts. Note that "root" is a special case, so
|
||||||
|
@ -224,4 +229,81 @@ of user '~a' is undeclared")
|
||||||
(user-account-supplementary-groups user)))
|
(user-account-supplementary-groups user)))
|
||||||
users)))
|
users)))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Service.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (user-group->gexp group)
|
||||||
|
"Turn GROUP, a <user-group> object, into a list-valued gexp suitable for
|
||||||
|
'active-groups'."
|
||||||
|
#~(list #$(user-group-name group)
|
||||||
|
#$(user-group-password group)
|
||||||
|
#$(user-group-id group)
|
||||||
|
#$(user-group-system? group)))
|
||||||
|
|
||||||
|
(define (user-account->gexp account)
|
||||||
|
"Turn ACCOUNT, a <user-account> object, into a list-valued gexp suitable for
|
||||||
|
'activate-users'."
|
||||||
|
#~`(#$(user-account-name account)
|
||||||
|
#$(user-account-uid account)
|
||||||
|
#$(user-account-group account)
|
||||||
|
#$(user-account-supplementary-groups account)
|
||||||
|
#$(user-account-comment account)
|
||||||
|
#$(user-account-home-directory account)
|
||||||
|
,#$(user-account-shell account) ; this one is a gexp
|
||||||
|
#$(user-account-password account)
|
||||||
|
#$(user-account-system? account)))
|
||||||
|
|
||||||
|
(define (account-activation accounts+groups)
|
||||||
|
"Return a gexp that activates ACCOUNTS+GROUPS, a list of <user-account> and
|
||||||
|
<user-group> objects. Raise an error if a user account refers to a undefined
|
||||||
|
group."
|
||||||
|
(define accounts
|
||||||
|
(filter user-account? accounts+groups))
|
||||||
|
|
||||||
|
(define user-specs
|
||||||
|
(map user-account->gexp accounts))
|
||||||
|
|
||||||
|
(define groups
|
||||||
|
(filter user-group? accounts+groups))
|
||||||
|
|
||||||
|
(define group-specs
|
||||||
|
(map user-group->gexp groups))
|
||||||
|
|
||||||
|
(assert-valid-users/groups accounts groups)
|
||||||
|
|
||||||
|
;; Add users and user groups.
|
||||||
|
#~(begin
|
||||||
|
(setenv "PATH"
|
||||||
|
(string-append #$(@ (gnu packages admin) shadow) "/sbin"))
|
||||||
|
(activate-users+groups (list #$@user-specs)
|
||||||
|
(list #$@group-specs))))
|
||||||
|
|
||||||
|
(define (etc-skel arguments)
|
||||||
|
"Filter out among ARGUMENTS things corresponding to skeletons, and return
|
||||||
|
the /etc/skel directory for those."
|
||||||
|
(let ((skels (filter pair? arguments)))
|
||||||
|
`(("skel" ,(skeleton-directory skels)))))
|
||||||
|
|
||||||
|
(define account-service-type
|
||||||
|
(service-type (name 'account)
|
||||||
|
|
||||||
|
;; Concatenate <user-account>, <user-group>, and skeleton
|
||||||
|
;; lists.
|
||||||
|
(compose concatenate)
|
||||||
|
(extend append)
|
||||||
|
|
||||||
|
(extensions
|
||||||
|
(list (service-extension activation-service-type
|
||||||
|
account-activation)
|
||||||
|
(service-extension etc-service-type
|
||||||
|
etc-skel)))))
|
||||||
|
|
||||||
|
(define (account-service accounts+groups skeletons)
|
||||||
|
"Return a <service> that takes care of user accounts and user groups, with
|
||||||
|
ACCOUNTS+GROUPS as its initial list of accounts and groups."
|
||||||
|
(service account-service-type
|
||||||
|
(append skeletons accounts+groups)))
|
||||||
|
|
||||||
;;; shadow.scm ends here
|
;;; shadow.scm ends here
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# List of source files which contain translatable strings.
|
# List of source files which contain translatable strings.
|
||||||
# This should be source files of the various tools, and not package modules.
|
# This should be source files of the various tools, and not package modules.
|
||||||
gnu/packages.scm
|
gnu/packages.scm
|
||||||
|
gnu/services.scm
|
||||||
gnu/system.scm
|
gnu/system.scm
|
||||||
gnu/services/dmd.scm
|
gnu/services/dmd.scm
|
||||||
gnu/system/shadow.scm
|
gnu/system/shadow.scm
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
|
;;; Copyright © 2015 Ludovic Courtès <ludo@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 (test-services)
|
||||||
|
#:use-module (gnu services)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-26)
|
||||||
|
#:use-module (srfi srfi-34)
|
||||||
|
#:use-module (srfi srfi-64))
|
||||||
|
|
||||||
|
(test-begin "services")
|
||||||
|
|
||||||
|
(test-equal "fold-services"
|
||||||
|
;; Make sure 'fold-services' returns the right result. The numbers come
|
||||||
|
;; from services of type T3; 'xyz 60' comes from the service of type T2,
|
||||||
|
;; where 60 = 15 × 4 = (1 + 2 + 3 + 4 + 5) × 4.
|
||||||
|
'(initial-value 5 4 3 2 1 xyz 60)
|
||||||
|
(let* ((t1 (service-type (name 't1) (extensions '())
|
||||||
|
(compose concatenate)
|
||||||
|
(extend cons)))
|
||||||
|
(t2 (service-type (name 't2)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension t1
|
||||||
|
(cut list 'xyz <>))))
|
||||||
|
(compose (cut reduce + 0 <>))
|
||||||
|
(extend *)))
|
||||||
|
(t3 (service-type (name 't3)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension t2 identity)
|
||||||
|
(service-extension t1 list)))))
|
||||||
|
(r (fold-services (cons* (service t1 'initial-value)
|
||||||
|
(service t2 4)
|
||||||
|
(map (lambda (x)
|
||||||
|
(service t3 x))
|
||||||
|
(iota 5 1)))
|
||||||
|
#:target-type t1)))
|
||||||
|
(and (eq? (service-kind r) t1)
|
||||||
|
(service-parameters r))))
|
||||||
|
|
||||||
|
(test-assert "fold-services, ambiguity"
|
||||||
|
(let* ((t1 (service-type (name 't1) (extensions '())
|
||||||
|
(compose concatenate)
|
||||||
|
(extend cons)))
|
||||||
|
(t2 (service-type (name 't2)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension t1 list)))))
|
||||||
|
(s (service t2 42)))
|
||||||
|
(guard (c ((ambiguous-target-service-error? c)
|
||||||
|
(and (eq? (ambiguous-target-service-error-target-type c)
|
||||||
|
t1)
|
||||||
|
(eq? (ambiguous-target-service-error-service c)
|
||||||
|
s))))
|
||||||
|
(fold-services (list (service t1 'first)
|
||||||
|
(service t1 'second)
|
||||||
|
s)
|
||||||
|
#:target-type t1)
|
||||||
|
#f)))
|
||||||
|
|
||||||
|
(test-assert "fold-services, missing target"
|
||||||
|
(let* ((t1 (service-type (name 't1) (extensions '())))
|
||||||
|
(t2 (service-type (name 't2)
|
||||||
|
(extensions
|
||||||
|
(list (service-extension t1 list)))))
|
||||||
|
(s (service t2 42)))
|
||||||
|
(guard (c ((missing-target-service-error? c)
|
||||||
|
(and (eq? (missing-target-service-error-target-type c)
|
||||||
|
t1)
|
||||||
|
(eq? (missing-target-service-error-service c)
|
||||||
|
s))))
|
||||||
|
(fold-services (list s) #:target-type t1)
|
||||||
|
#f)))
|
||||||
|
|
||||||
|
(test-end)
|
||||||
|
|
||||||
|
|
||||||
|
(exit (= (test-runner-fail-count (test-runner-current)) 0))
|
Reference in New Issue