diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2015-09-17 23:44:26 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2015-10-10 22:55:15 +0200 |
| commit | 0adfe95a3eee335847c3127edde3de550e692440 (patch) | |
| tree | 1c5a059d8f261f09254c0e420e61e1344c9edb45 | |
| parent | e79467f63a06811ba5dd8c8b0cc79553c5dd4e3a (diff) | |
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.
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | doc.am | 3 | ||||
| -rw-r--r-- | doc/guix.texi | 471 | ||||
| -rw-r--r-- | doc/images/service-graph.dot | 35 | ||||
| -rw-r--r-- | gnu-system.am | 1 | ||||
| -rw-r--r-- | gnu/services.scm | 455 | ||||
| -rw-r--r-- | gnu/services/avahi.scm | 122 | ||||
| -rw-r--r-- | gnu/services/base.scm | 1009 | ||||
| -rw-r--r-- | gnu/services/databases.scm | 144 | ||||
| -rw-r--r-- | gnu/services/dbus.scm | 178 | ||||
| -rw-r--r-- | gnu/services/desktop.scm | 645 | ||||
| -rw-r--r-- | gnu/services/dmd.scm | 78 | ||||
| -rw-r--r-- | gnu/services/lirc.scm | 80 | ||||
| -rw-r--r-- | gnu/services/networking.scm | 546 | ||||
| -rw-r--r-- | gnu/services/ssh.scm | 178 | ||||
| -rw-r--r-- | gnu/services/web.scm | 108 | ||||
| -rw-r--r-- | gnu/services/xorg.scm | 148 | ||||
| -rw-r--r-- | gnu/system.scm | 469 | ||||
| -rw-r--r-- | gnu/system/install.scm | 125 | ||||
| -rw-r--r-- | gnu/system/linux.scm | 30 | ||||
| -rw-r--r-- | gnu/system/shadow.scm | 96 | ||||
| -rw-r--r-- | po/guix/POTFILES.in | 1 | ||||
| -rw-r--r-- | tests/services.scm | 91 |
24 files changed, 3328 insertions, 1689 deletions
diff --git a/.gitignore b/.gitignore index a363c074ca7..e3f2ac2c21d 100644 --- a/.gitignore +++ b/.gitignore | |||
| @@ -129,3 +129,6 @@ GTAGS | |||
| 129 | /doc/images/coreutils-bag-graph.png | 129 | /doc/images/coreutils-bag-graph.png |
| 130 | /doc/images/coreutils-graph.png | 130 | /doc/images/coreutils-graph.png |
| 131 | /doc/images/coreutils-size-map.eps | 131 | /doc/images/coreutils-size-map.eps |
| 132 | /doc/images/service-graph.png | ||
| 133 | /doc/images/service-graph.eps | ||
| 134 | /doc/images/service-graph.pdf | ||
diff --git a/Makefile.am b/Makefile.am index a8dab5d3261..18fbd9d5786 100644 --- a/Makefile.am +++ b/Makefile.am | |||
| @@ -219,6 +219,7 @@ SCM_TESTS = \ | |||
| 219 | tests/size.scm \ | 219 | tests/size.scm \ |
| 220 | tests/graph.scm \ | 220 | tests/graph.scm \ |
| 221 | tests/file-systems.scm \ | 221 | tests/file-systems.scm \ |
| 222 | tests/services.scm \ | ||
| 222 | tests/containers.scm | 223 | tests/containers.scm |
| 223 | 224 | ||
| 224 | if HAVE_GUILE_JSON | 225 | if HAVE_GUILE_JSON |
| @@ -22,7 +22,8 @@ info_TEXINFOS = doc/guix.texi | |||
| 22 | DOT_FILES = \ | 22 | DOT_FILES = \ |
| 23 | doc/images/bootstrap-graph.dot \ | 23 | doc/images/bootstrap-graph.dot \ |
| 24 | doc/images/coreutils-graph.dot \ | 24 | doc/images/coreutils-graph.dot \ |
| 25 | doc/images/coreutils-bag-graph.dot | 25 | doc/images/coreutils-bag-graph.dot \ |
| 26 | doc/images/service-graph.dot | ||
| 26 | 27 | ||
| 27 | DOT_VECTOR_GRAPHICS = \ | 28 | DOT_VECTOR_GRAPHICS = \ |
| 28 | $(DOT_FILES:%.dot=%.eps) \ | 29 | $(DOT_FILES:%.dot=%.eps) \ |
diff --git a/doc/guix.texi b/doc/guix.texi index 1b25bd938fb..a3fa989d48b 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -182,6 +182,13 @@ Services | |||
| 182 | * Web Services:: Web servers. | 182 | * Web Services:: Web servers. |
| 183 | * Various Services:: Other services. | 183 | * Various Services:: Other services. |
| 184 | 184 | ||
| 185 | Defining Services | ||
| 186 | |||
| 187 | * Service Composition:: The model for composing services. | ||
| 188 | * Service Types and Services:: Types and services. | ||
| 189 | * Service Reference:: API reference. | ||
| 190 | * dmd Services:: A particular type of service. | ||
| 191 | |||
| 185 | Packaging Guidelines | 192 | Packaging Guidelines |
| 186 | 193 | ||
| 187 | * Software Freedom:: What may go into the distribution. | 194 | * Software Freedom:: What may go into the distribution. |
| @@ -5899,23 +5906,41 @@ Return a service that runs @code{syslogd}. If configuration file name | |||
| 5899 | settings. | 5906 | settings. |
| 5900 | @end deffn | 5907 | @end deffn |
| 5901 | 5908 | ||
| 5902 | @deffn {Scheme Procedure} guix-service [#:guix guix] @ | 5909 | @anchor{guix-configuration-type} |
| 5903 | [#:builder-group "guixbuild"] [#:build-accounts 10] @ | 5910 | @deftp {Data Type} guix-configuration |
| 5904 | [#:authorize-hydra-key? #t] [#:use-substitutes? #t] @ | 5911 | This data type represents the configuration of the Guix build daemon. |
| 5905 | [#:extra-options '()] | 5912 | @xref{Invoking guix-daemon}, for more information. |
| 5906 | Return a service that runs the build daemon from @var{guix}, and has | 5913 | |
| 5907 | @var{build-accounts} user accounts available under @var{builder-group}. | 5914 | @table @asis |
| 5915 | @item @code{guix} (default: @var{guix}) | ||
| 5916 | The Guix package to use. | ||
| 5908 | 5917 | ||
| 5909 | When @var{authorize-hydra-key?} is true, the @code{hydra.gnu.org} public key | 5918 | @item @code{build-group} (default: @code{"guixbuild"}) |
| 5910 | provided by @var{guix} is authorized upon activation, meaning that substitutes | 5919 | Name of the group for build user accounts. |
| 5911 | from @code{hydra.gnu.org} are used by default. | ||
| 5912 | 5920 | ||
| 5913 | If @var{use-substitutes?} is false, the daemon is run with | 5921 | @item @code{build-accounts} (default: @code{10}) |
| 5914 | @option{--no-substitutes} (@pxref{Invoking guix-daemon, | 5922 | Number of build user accounts to create. |
| 5915 | @option{--no-substitutes}}). | ||
| 5916 | 5923 | ||
| 5917 | Finally, @var{extra-options} is a list of additional command-line options | 5924 | @item @code{authorize-key?} (default: @code{#t}) |
| 5918 | passed to @command{guix-daemon}. | 5925 | Whether to authorize the substitute key for @code{hydra.gnu.org} |
| 5926 | (@pxref{Substitutes}). | ||
| 5927 | |||
| 5928 | @item @code{use-substitutes?} (default: @code{#t}) | ||
| 5929 | Whether to use substitutes. | ||
| 5930 | |||
| 5931 | @item @code{extra-options} (default: @code{'()}) | ||
| 5932 | List of extra command-line options for @command{guix-daemon}. | ||
| 5933 | |||
| 5934 | @item @code{lsof} (default: @var{lsof}) | ||
| 5935 | @itemx @code{lsh} (default: @var{lsh}) | ||
| 5936 | The lsof and lsh packages to use. | ||
| 5937 | |||
| 5938 | @end table | ||
| 5939 | @end deftp | ||
| 5940 | |||
| 5941 | @deffn {Scheme Procedure} guix-service @var{config} | ||
| 5942 | Return a service that runs the Guix build daemon according to | ||
| 5943 | @var{config}. | ||
| 5919 | @end deffn | 5944 | @end deffn |
| 5920 | 5945 | ||
| 5921 | @deffn {Scheme Procedure} udev-service [#:udev udev] | 5946 | @deffn {Scheme Procedure} udev-service [#:udev udev] |
| @@ -6179,11 +6204,10 @@ The @var{%desktop-services} variable can be used as the @code{services} | |||
| 6179 | field of an @code{operating-system} declaration (@pxref{operating-system | 6204 | field of an @code{operating-system} declaration (@pxref{operating-system |
| 6180 | Reference, @code{services}}). | 6205 | Reference, @code{services}}). |
| 6181 | 6206 | ||
| 6182 | The actual service definitions provided by @code{(gnu services desktop)} | 6207 | The actual service definitions provided by @code{(gnu services dbus)} |
| 6183 | are described below. | 6208 | and @code{(gnu services desktop)} are described below. |
| 6184 | 6209 | ||
| 6185 | @deffn {Scheme Procedure} dbus-service @var{services} @ | 6210 | @deffn {Scheme Procedure} dbus-service [#:dbus @var{dbus}] [#:services '()] |
| 6186 | [#:dbus @var{dbus}] | ||
| 6187 | Return a service that runs the ``system bus'', using @var{dbus}, with | 6211 | Return a service that runs the ``system bus'', using @var{dbus}, with |
| 6188 | support for @var{services}. | 6212 | support for @var{services}. |
| 6189 | 6213 | ||
| @@ -6197,8 +6221,7 @@ and policy files. For example, to allow avahi-daemon to use the system bus, | |||
| 6197 | @var{services} must be equal to @code{(list avahi)}. | 6221 | @var{services} must be equal to @code{(list avahi)}. |
| 6198 | @end deffn | 6222 | @end deffn |
| 6199 | 6223 | ||
| 6200 | @deffn {Scheme Procedure} elogind-service @ | 6224 | @deffn {Scheme Procedure} elogind-service [#:config @var{config}] |
| 6201 | [#:elogind @var{elogind}] [#:config @var{config}] | ||
| 6202 | Return a service that runs the @code{elogind} login and | 6225 | Return a service that runs the @code{elogind} login and |
| 6203 | seat management daemon. @uref{https://github.com/andywingo/elogind, | 6226 | seat management daemon. @uref{https://github.com/andywingo/elogind, |
| 6204 | Elogind} exposes a D-Bus interface that can be used to know which users | 6227 | Elogind} exposes a D-Bus interface that can be used to know which users |
| @@ -6957,54 +6980,378 @@ build users. | |||
| 6957 | @node Defining Services | 6980 | @node Defining Services |
| 6958 | @subsection Defining Services | 6981 | @subsection Defining Services |
| 6959 | 6982 | ||
| 6960 | The @code{(gnu services @dots{})} modules define several procedures that allow | 6983 | The previous sections how the available services and how one can combine |
| 6961 | users to declare the operating system's services (@pxref{Using the | 6984 | them in an @code{operating-system} declaration. But how do we define |
| 6962 | Configuration System}). These procedures are @emph{monadic | 6985 | them in the first place? And what is a service anyway? |
| 6963 | procedures}---i.e., procedures that return a monadic value in the store | ||
| 6964 | monad (@pxref{The Store Monad}). For examples of such procedures, | ||
| 6965 | @xref{Services}. | ||
| 6966 | |||
| 6967 | @cindex service definition | ||
| 6968 | The monadic value returned by those procedures is a @dfn{service | ||
| 6969 | definition}---a structure as returned by the @code{service} form. | ||
| 6970 | Service definitions specifies the inputs the service depends on, and an | ||
| 6971 | expression to start and stop the service. Behind the scenes, service | ||
| 6972 | definitions are ``translated'' into the form suitable for the | ||
| 6973 | configuration file of dmd, the init system (@pxref{Services,,, dmd, GNU | ||
| 6974 | dmd Manual}). | ||
| 6975 | |||
| 6976 | As an example, here is what the @code{nscd-service} procedure looks | ||
| 6977 | like: | ||
| 6978 | 6986 | ||
| 6979 | @lisp | 6987 | @menu |
| 6980 | (define (nscd-service) | 6988 | * Service Composition:: The model for composing services. |
| 6981 | (with-monad %store-monad | 6989 | * Service Types and Services:: Types and services. |
| 6982 | (return (service | 6990 | * Service Reference:: API reference. |
| 6983 | (documentation "Run libc's name service cache daemon.") | 6991 | * dmd Services:: A particular type of service. |
| 6984 | (provision '(nscd)) | 6992 | @end menu |
| 6985 | (activate #~(begin | 6993 | |
| 6986 | (use-modules (guix build utils)) | 6994 | @node Service Composition |
| 6987 | (mkdir-p "/var/run/nscd"))) | 6995 | @subsubsection Service Composition |
| 6988 | (start #~(make-forkexec-constructor | 6996 | |
| 6989 | (string-append #$glibc "/sbin/nscd") | 6997 | @cindex services |
| 6990 | "-f" "/dev/null" "--foreground")) | 6998 | @cindex daemons |
| 6991 | (stop #~(make-kill-destructor)) | 6999 | Here we define a @dfn{service} as, broadly, something that extends the |
| 6992 | (respawn? #f))))) | 7000 | operating system's functionality. Often a service is a process---a |
| 6993 | @end lisp | 7001 | @dfn{daemon}---started when the system boots: a secure shell server, a |
| 7002 | Web server, the Guix build daemon, etc. Sometimes a service is a daemon | ||
| 7003 | whose execution can be triggered by another daemon---e.g., an FTP server | ||
| 7004 | started by @command{inetd} or a D-Bus service activated by | ||
| 7005 | @command{dbus-daemon}. Occasionally, a service does not map to a | ||
| 7006 | daemon. For instance, the ``account'' service collects user accounts | ||
| 7007 | and makes sure they exist when the system runs; the ``udev'' service | ||
| 7008 | collects device management rules and makes them available to the eudev | ||
| 7009 | daemon; the @file{/etc} service populates the system's @file{/etc} | ||
| 7010 | directory. | ||
| 7011 | |||
| 7012 | GuixSD services are connected by @dfn{extensions}. For instance, the | ||
| 7013 | secure shell service @emph{extends} dmd---GuixSD's initialization system, | ||
| 7014 | running as PID@tie{}1---by giving it the command lines to start and stop | ||
| 7015 | the secure shell daemon (@pxref{Networking Services, | ||
| 7016 | @code{lsh-service}}); the UPower service extends the D-Bus service by | ||
| 7017 | passing it its @file{.service} specification, and extends the udev | ||
| 7018 | service by passing it device management rules (@pxref{Desktop Services, | ||
| 7019 | @code{upower-service}}); the Guix daemon service extends dmd by passing | ||
| 7020 | it the command lines to start and stop the daemon, and extends the | ||
| 7021 | account service by passing it a list of required build user accounts | ||
| 7022 | (@pxref{Base Services}). | ||
| 7023 | |||
| 7024 | All in all, services and their ``extends'' relations form a directed | ||
| 7025 | acyclic graph (DAG). If we represent services as boxes and extensions | ||
| 7026 | as arrows, a typical system might provide something like this: | ||
| 7027 | |||
| 7028 | @image{images/service-graph,,5in,Typical service extension graph.} | ||
| 7029 | |||
| 7030 | At the bottom, we see the @dfn{boot service}, which produces the boot | ||
| 7031 | script that is executed at boot time from the initial RAM disk. | ||
| 7032 | |||
| 7033 | @cindex service types | ||
| 7034 | Technically, developers can define @dfn{service types} to express these | ||
| 7035 | relations. There can be any number of services of a given type on the | ||
| 7036 | system---for instance, a system running two instances of the GNU secure | ||
| 7037 | shell server (lsh) has two instances of @var{lsh-service-type}, with | ||
| 7038 | different parameters. | ||
| 7039 | |||
| 7040 | The following section describes the programming interface for service | ||
| 7041 | types and services. | ||
| 7042 | |||
| 7043 | @node Service Types and Services | ||
| 7044 | @subsubsection Service Types and Services | ||
| 7045 | |||
| 7046 | A @dfn{service type} is a node in the DAG described above. Let us start | ||
| 7047 | with a simple example, the service type for the Guix build daemon | ||
| 7048 | (@pxref{Invoking guix-daemon}): | ||
| 7049 | |||
| 7050 | @example | ||
| 7051 | (define guix-service-type | ||
| 7052 | (service-type | ||
| 7053 | (name 'guix) | ||
| 7054 | (extensions | ||
| 7055 | (list (service-extension dmd-root-service-type guix-dmd-service) | ||
| 7056 | (service-extension account-service-type guix-accounts) | ||
| 7057 | (service-extension activation-service-type guix-activation))))) | ||
| 7058 | @end example | ||
| 6994 | 7059 | ||
| 6995 | @noindent | 7060 | @noindent |
| 6996 | The @code{activate}, @code{start}, and @code{stop} fields are G-expressions | 7061 | It defines a two things: |
| 6997 | (@pxref{G-Expressions}). The @code{activate} field contains a script to | 7062 | |
| 6998 | run at ``activation'' time; it makes sure that the @file{/var/run/nscd} | 7063 | @enumerate |
| 6999 | directory exists before @command{nscd} is started. | 7064 | @item |
| 7065 | A name, whose sole purpose is to make inspection and debugging easier. | ||
| 7066 | |||
| 7067 | @item | ||
| 7068 | A list of @dfn{service extensions}, where each extension designates the | ||
| 7069 | target service type and a procedure that, given the service's | ||
| 7070 | parameters, returns a list of object to extend the service of that type. | ||
| 7071 | |||
| 7072 | Every service type has at least one service extension. The only | ||
| 7073 | exception is the @dfn{boot service type}, which is the ultimate service. | ||
| 7074 | @end enumerate | ||
| 7075 | |||
| 7076 | In this example, @var{guix-service-type} extends three services: | ||
| 7077 | |||
| 7078 | @table @var | ||
| 7079 | @item dmd-root-service-type | ||
| 7080 | The @var{guix-dmd-service} procedure defines how the dmd service is | ||
| 7081 | extended. Namely, it returns a @code{<dmd-service>} object that defines | ||
| 7082 | how @command{guix-daemon} is started and stopped (@pxref{dmd Services}). | ||
| 7083 | |||
| 7084 | @item account-service-type | ||
| 7085 | This extension for this service is computed by @var{guix-accounts}, | ||
| 7086 | which returns a list of @code{user-group} and @code{user-account} | ||
| 7087 | objects representing the build user accounts (@pxref{Invoking | ||
| 7088 | guix-daemon}). | ||
| 7089 | |||
| 7090 | @item activation-service-type | ||
| 7091 | Here @var{guix-activation} is a procedure that returns a gexp, which is | ||
| 7092 | a code snippet to run at ``activation time''---e.g., when the service is | ||
| 7093 | booted. | ||
| 7094 | @end table | ||
| 7095 | |||
| 7096 | A service of this type is instantiated like this: | ||
| 7097 | |||
| 7098 | @example | ||
| 7099 | (service guix-service-type | ||
| 7100 | (guix-configuration | ||
| 7101 | (build-accounts 5) | ||
| 7102 | (use-substitutes? #f))) | ||
| 7103 | @end example | ||
| 7104 | |||
| 7105 | The second argument to the @code{service} form is a value representing | ||
| 7106 | the parameters of this specific service instance. | ||
| 7107 | @xref{guix-configuration-type, @code{guix-configuration}}, for | ||
| 7108 | information about the @code{guix-configuration} data type. | ||
| 7109 | |||
| 7110 | @var{guix-service-type} is quite simple because it extends other | ||
| 7111 | services but is not extensible itself. | ||
| 7112 | |||
| 7113 | @c @subsubsubsection Extensible Service Types | ||
| 7114 | |||
| 7115 | The service type for an @emph{extensible} service looks like this: | ||
| 7116 | |||
| 7117 | @example | ||
| 7118 | (define udev-service-type | ||
| 7119 | (service-type (name 'udev) | ||
| 7120 | (extensions | ||
| 7121 | (list (service-extension dmd-root-service-type | ||
| 7122 | udev-dmd-service))) | ||
| 7123 | |||
| 7124 | (compose concatenate) ;concatenate the list of rules | ||
| 7125 | (extend (lambda (config rules) | ||
| 7126 | (match config | ||
| 7127 | (($ <udev-configuration> udev initial-rules) | ||
| 7128 | (udev-configuration | ||
| 7129 | (udev udev) ;the udev package to use | ||
| 7130 | (rules (append initial-rules rules))))))))) | ||
| 7131 | @end example | ||
| 7132 | |||
| 7133 | This is the service type for the | ||
| 7134 | @uref{https://wiki.gentoo.org/wiki/Project:Eudev, eudev device | ||
| 7135 | management daemon}. Compared to the previous example, in addition to an | ||
| 7136 | extension of @var{dmd-root-service-type}, we see two new fields: | ||
| 7137 | |||
| 7138 | @table @code | ||
| 7139 | @item compose | ||
| 7140 | This is the procedure to @dfn{compose} the list of extensions to | ||
| 7141 | services of this type. | ||
| 7142 | |||
| 7143 | Services can extend the udev service by passing it lists of rules; we | ||
| 7144 | compose those extensions simply by concatenating them. | ||
| 7145 | |||
| 7146 | @item extend | ||
| 7147 | This procedure defines how the service's value is @dfn{extended} with | ||
| 7148 | the composition of the extensions. | ||
| 7149 | |||
| 7150 | Udev extensions are composed into a list of rules, but the udev service | ||
| 7151 | value is itself a @code{<udev-configuration>} record. So here, we | ||
| 7152 | extend that record by appending the list of rules is contains to the | ||
| 7153 | list of contributed rules. | ||
| 7154 | @end table | ||
| 7155 | |||
| 7156 | There can be only one instance of an extensible service type such as | ||
| 7157 | @var{udev-service-type}. If there were more, the | ||
| 7158 | @code{service-extension} specifications would be ambiguous. | ||
| 7159 | |||
| 7160 | Still here? The next section provides a reference of the programming | ||
| 7161 | interface for services. | ||
| 7162 | |||
| 7163 | @node Service Reference | ||
| 7164 | @subsubsection Service Reference | ||
| 7165 | |||
| 7166 | We have seen an overview of service types (@pxref{Service Types and | ||
| 7167 | Services}). This section provides a reference on how to manipulate | ||
| 7168 | services and service types. This interface is provided by the | ||
| 7169 | @code{(gnu services)} module. | ||
| 7170 | |||
| 7171 | @deffn {Scheme Procedure} service @var{type} @var{value} | ||
| 7172 | Return a new service of @var{type}, a @code{<service-type>} object (see | ||
| 7173 | below.) @var{value} can be any object; it represents the parameters of | ||
| 7174 | this particular service instance. | ||
| 7175 | @end deffn | ||
| 7176 | |||
| 7177 | @deffn {Scheme Procedure} service? @var{obj} | ||
| 7178 | Return true if @var{obj} is a service. | ||
| 7179 | @end deffn | ||
| 7180 | |||
| 7181 | @deffn {Scheme Procedure} service-kind @var{service} | ||
| 7182 | Return the type of @var{service}---i.e., a @code{<service-type>} object. | ||
| 7183 | @end deffn | ||
| 7184 | |||
| 7185 | @deffn {Scheme Procedure} service-parameters @var{service} | ||
| 7186 | Return the value associated with @var{service}. It represents its | ||
| 7187 | parameters. | ||
| 7188 | @end deffn | ||
| 7189 | |||
| 7190 | Here is an example of how a service is created and manipulated: | ||
| 7191 | |||
| 7192 | @example | ||
| 7193 | (define s | ||
| 7194 | (service nginx-service-type | ||
| 7195 | (nginx-configuration | ||
| 7196 | (nginx nginx) | ||
| 7197 | (log-directory log-directory) | ||
| 7198 | (run-directory run-directory) | ||
| 7199 | (file config-file)))) | ||
| 7200 | |||
| 7201 | (service? s) | ||
| 7202 | @result{} #t | ||
| 7203 | |||
| 7204 | (eq? (service-kind s) nginx-service-type) | ||
| 7205 | @result{} #t | ||
| 7206 | @end example | ||
| 7207 | |||
| 7208 | @deftp {Data Type} service-type | ||
| 7209 | @cindex service type | ||
| 7210 | This is the representation of a @dfn{service type} (@pxref{Service Types | ||
| 7211 | and Services}). | ||
| 7212 | |||
| 7213 | @table @asis | ||
| 7214 | @item @code{name} | ||
| 7215 | This is a symbol, used only to simplify inspection and debugging. | ||
| 7216 | |||
| 7217 | @item @code{extensions} | ||
| 7218 | A non-empty list of @code{<service-extension>} objects (see below.) | ||
| 7219 | |||
| 7220 | @item @code{compose} (default: @code{#f}) | ||
| 7221 | If this is @code{#f}, then the service type denotes services that cannot | ||
| 7222 | be extended---i.e., services that do not receive ``values'' from other | ||
| 7223 | services. | ||
| 7224 | |||
| 7225 | Otherwise, it must be a one-argument procedure. The procedure is called | ||
| 7226 | by @code{fold-services} and is passed a list of values collected from | ||
| 7227 | extensions. It must return a value that is a valid parameter value for | ||
| 7228 | the service instance. | ||
| 7229 | |||
| 7230 | @item @code{extend} (default: @code{#f}) | ||
| 7231 | If this is @code{#f}, services of this type cannot be extended. | ||
| 7232 | |||
| 7233 | Otherwise, it must be a two-argument procedure: @code{fold-services} | ||
| 7234 | calls it, passing it the service's initial value as the first argument | ||
| 7235 | and the result of applying @code{compose} to the extension values as the | ||
| 7236 | second argument. | ||
| 7237 | @end table | ||
| 7238 | |||
| 7239 | @xref{Service Types and Services}, for examples. | ||
| 7240 | @end deftp | ||
| 7241 | |||
| 7242 | @deffn {Scheme Procedure} service-extension @var{target-type} @ | ||
| 7243 | @var{compute} | ||
| 7244 | Return a new extension for services of type @var{target-type}. | ||
| 7245 | @var{compute} must be a one-argument procedure: @code{fold-services} | ||
| 7246 | calls it, passing it the value associated with the service that provides | ||
| 7247 | the extension; it must return a valid value for the target service. | ||
| 7248 | @end deffn | ||
| 7249 | |||
| 7250 | @deffn {Scheme Procedure} service-extension? @var{obj} | ||
| 7251 | Return true if @var{obj} is a service extension. | ||
| 7252 | @end deffn | ||
| 7253 | |||
| 7254 | At the core of the service abstraction lies the @code{fold-services} | ||
| 7255 | procedure, which is responsible for ``compiling'' a list of services | ||
| 7256 | down to a single boot script. In essence, it propagates service | ||
| 7257 | extensions down the service graph, updating each node parameters on the | ||
| 7258 | way, until it reaches the root node. | ||
| 7259 | |||
| 7260 | @deffn {Scheme Procedure} fold-services @var{services} @ | ||
| 7261 | [#:target-type @var{boot-service-type}] | ||
| 7262 | Fold @var{services} by propagating their extensions down to the root of | ||
| 7263 | type @var{target-type}; return the root service adjusted accordingly. | ||
| 7264 | @end deffn | ||
| 7265 | |||
| 7266 | Lastly, the @code{(gnu services)} module also defines several essential | ||
| 7267 | service types, some of which are listed below. | ||
| 7268 | |||
| 7269 | @defvr {Scheme Variable} boot-service-type | ||
| 7270 | The type of the ``boot service'', which is the root of the service | ||
| 7271 | graph. | ||
| 7272 | @end defvr | ||
| 7273 | |||
| 7274 | @defvr {Scheme Variable} etc-service-type | ||
| 7275 | The type of the @file{/etc} service. This service can be extended by | ||
| 7276 | passing it name/file tuples such as: | ||
| 7277 | |||
| 7278 | @example | ||
| 7279 | (list `("issue" ,(plain-file "issue" "Welcome!\n"))) | ||
| 7280 | @end example | ||
| 7281 | |||
| 7282 | In this example, the effect would be to add an @file{/etc/issue} file | ||
| 7283 | pointing to the given file. | ||
| 7284 | @end defvr | ||
| 7285 | |||
| 7286 | @defvr {Scheme Variable} setuid-program-service-type | ||
| 7287 | Type for the ``setuid-program service''. This service collects lists of | ||
| 7288 | executable file names, passed as gexps, and adds them to the set of | ||
| 7289 | setuid-root programs on the system (@pxref{Setuid Programs}). | ||
| 7290 | @end defvr | ||
| 7291 | |||
| 7292 | |||
| 7293 | @node dmd Services | ||
| 7294 | @subsubsection dmd Services | ||
| 7295 | |||
| 7296 | @cindex PID 1 | ||
| 7297 | @cindex init system | ||
| 7298 | The @code{(gnu services dmd)} provides a way to define services managed | ||
| 7299 | by GNU@tie{}dmd, which is GuixSD initialization system---the first | ||
| 7300 | process that is started when the system boots, aka. PID@tie{}1 | ||
| 7301 | (@pxref{Introduction,,, dmd, GNU dmd Manual}). The | ||
| 7302 | @var{%dmd-root-service} represents PID@tie{}1, of type | ||
| 7303 | @var{dmd-root-service-type}; it can be extended by passing it lists of | ||
| 7304 | @code{<dmd-service>} objects. | ||
| 7305 | |||
| 7306 | @deftp {Data Type} dmd-service | ||
| 7307 | The data type representing a service managed by dmd. | ||
| 7308 | |||
| 7309 | @table @asis | ||
| 7310 | @item @code{provision} | ||
| 7311 | This is a list of symbols denoting what the service provides. | ||
| 7000 | 7312 | ||
| 7313 | These are the names that may be passed to @command{deco start}, | ||
| 7314 | @command{deco status}, and similar commands (@pxref{Invoking deco,,, | ||
| 7315 | dmd, GNU dmd Manual}). @xref{Slots of services, the @code{provides} | ||
| 7316 | slot,, dmd, GNU dmd Manual}, for details. | ||
| 7317 | |||
| 7318 | @item @code{requirements} (default: @code{'()}) | ||
| 7319 | List of symbols denoting the dmd services this one depends on. | ||
| 7320 | |||
| 7321 | @item @code{respawn?} (default: @code{#t}) | ||
| 7322 | Whether to restart the service when it stops, for instance when the | ||
| 7323 | underlying process dies. | ||
| 7324 | |||
| 7325 | @item @code{start} | ||
| 7326 | @itemx @code{stop} (default: @code{#~(const #f)}) | ||
| 7001 | The @code{start} and @code{stop} fields refer to dmd's facilities to | 7327 | The @code{start} and @code{stop} fields refer to dmd's facilities to |
| 7002 | start and stop processes (@pxref{Service De- and Constructors,,, dmd, | 7328 | start and stop processes (@pxref{Service De- and Constructors,,, dmd, |
| 7003 | GNU dmd Manual}). The @code{provision} field specifies the name under | 7329 | GNU dmd Manual}). They are given as G-expressions that get expanded in |
| 7004 | which this service is known to dmd, and @code{documentation} specifies | 7330 | the dmd configuration file (@pxref{G-Expressions}). |
| 7005 | on-line documentation. Thus, the commands @command{deco start ncsd}, | 7331 | |
| 7006 | @command{deco stop nscd}, and @command{deco doc nscd} will do what you | 7332 | @item @code{documentation} |
| 7007 | would expect (@pxref{Invoking deco,,, dmd, GNU dmd Manual}). | 7333 | A documentation string, as shown when running: |
| 7334 | |||
| 7335 | @example | ||
| 7336 | deco doc @var{service-name} | ||
| 7337 | @end example | ||
| 7338 | |||
| 7339 | where @var{service-name} is one of the symbols in @var{provision} | ||
| 7340 | (@pxref{Invoking deco,,, dmd, GNU dmd Manual}). | ||
| 7341 | @end table | ||
| 7342 | @end deftp | ||
| 7343 | |||
| 7344 | @defvr {Scheme Variable} dmd-root-service-type | ||
| 7345 | The service type for the dmd ``root service''---i.e., PID@tie{}1. | ||
| 7346 | |||
| 7347 | This is the service type that extensions target when they want to create | ||
| 7348 | dmd services (@pxref{Service Types and Services}, for an example). Each | ||
| 7349 | extension must pass a list of @code{<dmd-service>}. | ||
| 7350 | @end defvr | ||
| 7351 | |||
| 7352 | @defvr {Scheme Variable} %dmd-root-service | ||
| 7353 | This service represents PID@tie{}1. | ||
| 7354 | @end defvr | ||
| 7008 | 7355 | ||
| 7009 | 7356 | ||
| 7010 | @node Installing Debugging Files | 7357 | @node Installing Debugging Files |
diff --git a/doc/images/service-graph.dot b/doc/images/service-graph.dot new file mode 100644 index 00000000000..3397b878e96 --- /dev/null +++ b/doc/images/service-graph.dot | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | digraph "Service Type Dependencies" { | ||
| 2 | dmd [shape = box, fontname = Helvetica]; | ||
| 3 | pam [shape = box, fontname = Helvetica]; | ||
| 4 | etc [shape = box, fontname = Helvetica]; | ||
| 5 | accounts [shape = box, fontname = Helvetica]; | ||
| 6 | activation [shape = box, fontname = Helvetica]; | ||
| 7 | boot [shape = house, fontname = Helvetica]; | ||
| 8 | lshd -> dmd; | ||
| 9 | lshd -> pam; | ||
| 10 | udev -> dmd; | ||
| 11 | nscd -> dmd [label = "extends"]; | ||
| 12 | "nss-mdns" -> nscd; | ||
| 13 | "kvm-rules" -> udev; | ||
| 14 | colord -> udev; | ||
| 15 | dbus -> dmd; | ||
| 16 | colord -> dbus; | ||
| 17 | upower -> udev; | ||
| 18 | upower -> dbus; | ||
| 19 | polkit -> dbus; | ||
| 20 | polkit -> pam; | ||
| 21 | elogind -> dbus; | ||
| 22 | elogind -> udev; | ||
| 23 | elogind -> polkit [label = "extends"]; | ||
| 24 | dmd -> boot; | ||
| 25 | colord -> accounts; | ||
| 26 | accounts -> activation; | ||
| 27 | accounts -> etc; | ||
| 28 | etc -> activation; | ||
| 29 | activation -> boot; | ||
| 30 | pam -> etc; | ||
| 31 | elogind -> pam; | ||
| 32 | guix -> dmd; | ||
| 33 | guix -> activation; | ||
| 34 | guix -> accounts; | ||
| 35 | } | ||
diff --git a/gnu-system.am b/gnu-system.am index c2dc323a617..64260dd3000 100644 --- a/gnu-system.am +++ b/gnu-system.am | |||
| @@ -348,6 +348,7 @@ GNU_SYSTEM_MODULES = \ | |||
| 348 | gnu/services/avahi.scm \ | 348 | gnu/services/avahi.scm \ |
| 349 | gnu/services/base.scm \ | 349 | gnu/services/base.scm \ |
| 350 | gnu/services/databases.scm \ | 350 | gnu/services/databases.scm \ |
| 351 | gnu/services/dbus.scm \ | ||
| 351 | gnu/services/desktop.scm \ | 352 | gnu/services/desktop.scm \ |
| 352 | gnu/services/dmd.scm \ | 353 | gnu/services/dmd.scm \ |
| 353 | gnu/services/lirc.scm \ | 354 | gnu/services/lirc.scm \ |
diff --git a/gnu/services.scm b/gnu/services.scm index 43e51b998c9..fdfa569b239 100644 --- a/gnu/services.scm +++ b/gnu/services.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; | 3 | ;;; |
| 4 | ;;; This file is part of GNU Guix. | 4 | ;;; This file is part of GNU Guix. |
| 5 | ;;; | 5 | ;;; |
| @@ -18,49 +18,428 @@ | |||
| 18 | 18 | ||
| 19 | (define-module (gnu services) | 19 | (define-module (gnu services) |
| 20 | #:use-module (guix gexp) | 20 | #:use-module (guix gexp) |
| 21 | #:use-module (guix monads) | ||
| 22 | #:use-module (guix store) | ||
| 21 | #:use-module (guix records) | 23 | #:use-module (guix records) |
| 22 | #:export (service? | 24 | #:use-module (guix sets) |
| 25 | #:use-module (guix ui) | ||
| 26 | #:use-module (gnu packages base) | ||
| 27 | #:use-module (gnu packages bash) | ||
| 28 | #:use-module (srfi srfi-1) | ||
| 29 | #:use-module (srfi srfi-9) | ||
| 30 | #:use-module (srfi srfi-9 gnu) | ||
| 31 | #:use-module (srfi srfi-26) | ||
| 32 | #:use-module (srfi srfi-34) | ||
| 33 | #:use-module (srfi srfi-35) | ||
| 34 | #:use-module (ice-9 vlist) | ||
| 35 | #:use-module (ice-9 match) | ||
| 36 | #:export (service-extension | ||
| 37 | service-extension? | ||
| 38 | |||
| 39 | service-type | ||
| 40 | service-type? | ||
| 41 | |||
| 23 | service | 42 | service |
| 24 | service-documentation | 43 | service? |
| 25 | service-provision | 44 | service-kind |
| 26 | service-requirement | 45 | service-parameters |
| 27 | service-respawn? | 46 | |
| 28 | service-start | 47 | fold-services |
| 29 | service-stop | 48 | |
| 30 | service-auto-start? | 49 | service-error? |
| 31 | service-activate | 50 | missing-target-service-error? |
| 32 | service-user-accounts | 51 | missing-target-service-error-service |
| 33 | service-user-groups | 52 | missing-target-service-error-target-type |
| 34 | service-pam-services)) | 53 | ambiguous-target-service-error? |
| 35 | 54 | ambiguous-target-service-error-service | |
| 36 | ;;; Commentary: | 55 | ambiguous-target-service-error-target-type |
| 56 | |||
| 57 | boot-service-type | ||
| 58 | activation-service-type | ||
| 59 | activation-service->script | ||
| 60 | etc-service-type | ||
| 61 | etc-directory | ||
| 62 | setuid-program-service-type | ||
| 63 | firmware-service-type | ||
| 64 | |||
| 65 | %boot-service | ||
| 66 | %activation-service | ||
| 67 | etc-service | ||
| 68 | |||
| 69 | file-union)) ;XXX: for lack of a better place | ||
| 70 | |||
| 71 | ;;; Comment: | ||
| 72 | ;;; | ||
| 73 | ;;; This module defines a broad notion of "service types" and "services." | ||
| 37 | ;;; | 74 | ;;; |
| 38 | ;;; System services as cajoled by dmd. | 75 | ;;; A service type describe how its instances extend instances of other |
| 76 | ;;; service types. For instance, some services extend the instance of | ||
| 77 | ;;; ACCOUNT-SERVICE-TYPE by providing it with accounts and groups to create; | ||
| 78 | ;;; others extend DMD-ROOT-SERVICE-TYPE by passing it instances of | ||
| 79 | ;;; <dmd-service>. | ||
| 80 | ;;; | ||
| 81 | ;;; When applicable, the service type defines how it can itself be extended, | ||
| 82 | ;;; by providing one procedure to compose extensions, and one procedure to | ||
| 83 | ;;; extend itself. | ||
| 84 | ;;; | ||
| 85 | ;;; A notable service type is BOOT-SERVICE-TYPE, which has a single instance, | ||
| 86 | ;;; %BOOT-SERVICE. %BOOT-SERVICE constitutes the root of the service DAG. It | ||
| 87 | ;;; produces the boot script that the initrd loads. | ||
| 88 | ;;; | ||
| 89 | ;;; The 'fold-services' procedure can be passed a list of procedures, which it | ||
| 90 | ;;; "folds" by propagating extensions down the graph; it returns the root | ||
| 91 | ;;; service after the applying all its extensions. | ||
| 39 | ;;; | 92 | ;;; |
| 40 | ;;; Code: | 93 | ;;; Code: |
| 41 | 94 | ||
| 42 | (define-record-type* <service> | 95 | (define-record-type <service-extension> |
| 43 | service make-service | 96 | (service-extension target compute) |
| 97 | service-extension? | ||
| 98 | (target service-extension-target) ;<service-type> | ||
| 99 | (compute service-extension-compute)) ;params -> params | ||
| 100 | |||
| 101 | (define-record-type* <service-type> service-type make-service-type | ||
| 102 | service-type? | ||
| 103 | (name service-type-name) ;symbol (for debugging) | ||
| 104 | |||
| 105 | ;; Things extended by services of this type. | ||
| 106 | (extensions service-type-extensions) ;list of <service-extensions> | ||
| 107 | |||
| 108 | ;; Given a list of extensions, "compose" them. | ||
| 109 | (compose service-type-compose ;list of Any -> Any | ||
| 110 | (default #f)) | ||
| 111 | |||
| 112 | ;; Extend the services' own parameters with the extension composition. | ||
| 113 | (extend service-type-extend ;list of Any -> parameters | ||
| 114 | (default #f))) | ||
| 115 | |||
| 116 | (define (write-service-type type port) | ||
| 117 | (format port "#<service-type ~a ~a>" | ||
| 118 | (service-type-name type) | ||
| 119 | (number->string (object-address type) 16))) | ||
| 120 | |||
| 121 | (set-record-type-printer! <service-type> write-service-type) | ||
| 122 | |||
| 123 | ;; Services of a given type. | ||
| 124 | (define-record-type <service> | ||
| 125 | (service type parameters) | ||
| 44 | service? | 126 | service? |
| 45 | (documentation service-documentation ; string | 127 | (type service-kind) |
| 46 | (default "[No documentation.]")) | 128 | (parameters service-parameters)) |
| 47 | (provision service-provision) ; list of symbols | 129 | |
| 48 | (requirement service-requirement ; list of symbols | 130 | |
| 49 | (default '())) | 131 | |
| 50 | (respawn? service-respawn? ; Boolean | 132 | |
| 51 | (default #t)) | 133 | ;;; |
| 52 | (start service-start) ; g-expression (procedure) | 134 | ;;; Core services. |
| 53 | (stop service-stop ; g-expression (procedure) | 135 | ;;; |
| 54 | (default #~(const #f))) | 136 | |
| 55 | (auto-start? service-auto-start? ; Boolean | 137 | (define (compute-boot-script mexps) |
| 56 | (default #t)) | 138 | (mlet %store-monad ((gexps (sequence %store-monad mexps))) |
| 57 | (user-accounts service-user-accounts ; list of <user-account> | 139 | (gexp->file "boot" |
| 58 | (default '())) | 140 | #~(begin |
| 59 | (user-groups service-user-groups ; list of <user-groups> | 141 | (use-modules (guix build utils)) |
| 60 | (default '())) | 142 | |
| 61 | (pam-services service-pam-services ; list of <pam-service> | 143 | ;; Clean out /tmp and /var/run. |
| 62 | (default '())) | 144 | ;; |
| 63 | (activate service-activate ; gexp | 145 | ;; XXX This needs to happen before service activations, so |
| 64 | (default #f))) | 146 | ;; it has to be here, but this also implicitly assumes |
| 147 | ;; that /tmp and /var/run are on the root partition. | ||
| 148 | (false-if-exception (delete-file-recursively "/tmp")) | ||
| 149 | (false-if-exception (delete-file-recursively "/var/run")) | ||
| 150 | (false-if-exception (mkdir "/tmp")) | ||
| 151 | (false-if-exception (chmod "/tmp" #o1777)) | ||
| 152 | (false-if-exception (mkdir "/var/run")) | ||
| 153 | (false-if-exception (chmod "/var/run" #o755)) | ||
| 154 | |||
| 155 | ;; Activate the system and spawn dmd. | ||
| 156 | #$@gexps)))) | ||
| 157 | |||
| 158 | (define (second-argument a b) b) | ||
| 159 | |||
| 160 | (define boot-service-type | ||
| 161 | ;; The service of this type is extended by being passed gexps as monadic | ||
| 162 | ;; values. It aggregates them in a single script, as a monadic value, which | ||
| 163 | ;; becomes its 'parameters'. It is the only service that extends nothing. | ||
| 164 | (service-type (name 'boot) | ||
| 165 | (extensions '()) | ||
| 166 | (compose compute-boot-script) | ||
| 167 | (extend second-argument))) | ||
| 168 | |||
| 169 | (define %boot-service | ||
| 170 | ;; This is the ultimate service, the root of the service DAG. | ||
| 171 | (service boot-service-type #t)) | ||
| 172 | |||
| 173 | (define* (file-union name files) ;FIXME: Factorize. | ||
| 174 | "Return a <computed-file> that builds a directory containing all of FILES. | ||
| 175 | Each item in FILES must be a list where the first element is the file name to | ||
| 176 | use in the new directory, and the second element is a gexp denoting the target | ||
| 177 | file." | ||
| 178 | (computed-file name | ||
| 179 | #~(begin | ||
| 180 | (mkdir #$output) | ||
| 181 | (chdir #$output) | ||
| 182 | #$@(map (match-lambda | ||
| 183 | ((target source) | ||
| 184 | #~(symlink #$source #$target))) | ||
| 185 | files)))) | ||
| 186 | |||
| 187 | (define (directory-union name things) | ||
| 188 | "Return a directory that is the union of THINGS." | ||
| 189 | (match things | ||
| 190 | ((one) | ||
| 191 | ;; Only one thing; return it. | ||
| 192 | one) | ||
| 193 | (_ | ||
| 194 | (computed-file name | ||
| 195 | #~(begin | ||
| 196 | (use-modules (guix build union)) | ||
| 197 | (union-build #$output '#$things)) | ||
| 198 | #:modules '((guix build union)))))) | ||
| 199 | |||
| 200 | (define (modprobe-wrapper) | ||
| 201 | "Return a wrapper for the 'modprobe' command that knows where modules live. | ||
| 202 | |||
| 203 | This wrapper is typically invoked by the Linux kernel ('call_modprobe', in | ||
| 204 | kernel/kmod.c), a situation where the 'LINUX_MODULE_DIRECTORY' environment | ||
| 205 | variable is not set---hence the need for this wrapper." | ||
| 206 | (let ((modprobe "/run/current-system/profile/bin/modprobe")) | ||
| 207 | (gexp->script "modprobe" | ||
| 208 | #~(begin | ||
| 209 | (setenv "LINUX_MODULE_DIRECTORY" | ||
| 210 | "/run/booted-system/kernel/lib/modules") | ||
| 211 | (apply execl #$modprobe | ||
| 212 | (cons #$modprobe (cdr (command-line)))))))) | ||
| 213 | |||
| 214 | (define* (activation-service->script service) | ||
| 215 | "Return as a monadic value the activation script for SERVICE, a service of | ||
| 216 | ACTIVATION-SCRIPT-TYPE." | ||
| 217 | (activation-script (service-parameters service))) | ||
| 218 | |||
| 219 | (define (activation-script gexps) | ||
| 220 | "Return the system's activation script, which evaluates GEXPS." | ||
| 221 | (define %modules | ||
| 222 | '((gnu build activation) | ||
| 223 | (gnu build linux-boot) | ||
| 224 | (gnu build linux-modules) | ||
| 225 | (gnu build file-systems) | ||
| 226 | (guix build utils) | ||
| 227 | (guix build syscalls) | ||
| 228 | (guix elf))) | ||
| 229 | |||
| 230 | (define (service-activations) | ||
| 231 | ;; Return the activation scripts for SERVICES. | ||
| 232 | (mapm %store-monad | ||
| 233 | (cut gexp->file "activate-service" <>) | ||
| 234 | gexps)) | ||
| 235 | |||
| 236 | (mlet* %store-monad ((actions (service-activations)) | ||
| 237 | (modules (imported-modules %modules)) | ||
| 238 | (compiled (compiled-modules %modules)) | ||
| 239 | (modprobe (modprobe-wrapper))) | ||
| 240 | (gexp->file "activate" | ||
| 241 | #~(begin | ||
| 242 | (eval-when (expand load eval) | ||
| 243 | ;; Make sure 'use-modules' below succeeds. | ||
| 244 | (set! %load-path (cons #$modules %load-path)) | ||
| 245 | (set! %load-compiled-path | ||
| 246 | (cons #$compiled %load-compiled-path))) | ||
| 247 | |||
| 248 | (use-modules (gnu build activation)) | ||
| 249 | |||
| 250 | ;; Make sure /bin/sh is valid and current. | ||
| 251 | (activate-/bin/sh | ||
| 252 | (string-append #$(canonical-package bash) "/bin/sh")) | ||
| 253 | |||
| 254 | ;; Tell the kernel to use our 'modprobe' command. | ||
| 255 | (activate-modprobe #$modprobe) | ||
| 256 | |||
| 257 | ;; Let users debug their own processes! | ||
| 258 | (activate-ptrace-attach) | ||
| 259 | |||
| 260 | ;; Run the services' activation snippets. | ||
| 261 | ;; TODO: Use 'load-compiled'. | ||
| 262 | (for-each primitive-load '#$actions) | ||
| 263 | |||
| 264 | ;; Set up /run/current-system. | ||
| 265 | (activate-current-system))))) | ||
| 266 | |||
| 267 | (define (gexps->activation-gexp gexps) | ||
| 268 | "Return a gexp that runs the activation script containing GEXPS." | ||
| 269 | (mlet %store-monad ((script (activation-script gexps))) | ||
| 270 | (return #~(primitive-load #$script)))) | ||
| 271 | |||
| 272 | (define activation-service-type | ||
| 273 | (service-type (name 'activate) | ||
| 274 | (extensions | ||
| 275 | (list (service-extension boot-service-type | ||
| 276 | gexps->activation-gexp))) | ||
| 277 | (compose append) | ||
| 278 | (extend second-argument))) | ||
| 279 | |||
| 280 | (define %activation-service | ||
| 281 | ;; The activation service produces the activation script from the gexps it | ||
| 282 | ;; receives. | ||
| 283 | (service activation-service-type #t)) | ||
| 284 | |||
| 285 | (define (etc-directory service) | ||
| 286 | "Return the directory for SERVICE, a service of type ETC-SERVICE-TYPE." | ||
| 287 | (files->etc-directory (service-parameters service))) | ||
| 288 | |||
| 289 | (define (files->etc-directory files) | ||
| 290 | (file-union "etc" files)) | ||
| 291 | |||
| 292 | (define etc-service-type | ||
| 293 | (service-type (name 'etc) | ||
| 294 | (extensions | ||
| 295 | (list | ||
| 296 | (service-extension activation-service-type | ||
| 297 | (lambda (files) | ||
| 298 | (let ((etc | ||
| 299 | (files->etc-directory files))) | ||
| 300 | #~(activate-etc #$etc)))))) | ||
| 301 | (compose concatenate) | ||
| 302 | (extend append))) | ||
| 303 | |||
| 304 | (define (etc-service files) | ||
| 305 | "Return a new service of ETC-SERVICE-TYPE that populates /etc with FILES. | ||
| 306 | FILES must be a list of name/file-like object pairs." | ||
| 307 | (service etc-service-type files)) | ||
| 308 | |||
| 309 | (define setuid-program-service-type | ||
| 310 | (service-type (name 'setuid-program) | ||
| 311 | (extensions | ||
| 312 | (list (service-extension activation-service-type | ||
| 313 | (lambda (programs) | ||
| 314 | #~(activate-setuid-programs | ||
| 315 | (list #$@programs)))))) | ||
| 316 | (compose concatenate) | ||
| 317 | (extend append))) | ||
| 318 | |||
| 319 | (define (firmware->activation-gexp firmware) | ||
| 320 | "Return a gexp to make the packages listed in FIRMWARE loadable by the | ||
| 321 | kernel." | ||
| 322 | (let ((directory (directory-union "firmware" firmware))) | ||
| 323 | ;; Tell the kernel where firmware is. | ||
| 324 | #~(activate-firmware (string-append #$directory "/lib/firmware")))) | ||
| 325 | |||
| 326 | (define firmware-service-type | ||
| 327 | ;; The service that collects firmware. | ||
| 328 | (service-type (name 'firmware) | ||
| 329 | (extensions | ||
| 330 | (list (service-extension activation-service-type | ||
| 331 | firmware->activation-gexp))) | ||
| 332 | (compose concatenate) | ||
| 333 | (extend append))) | ||
| 334 | |||
| 335 | |||
| 336 | ;;; | ||
| 337 | ;;; Service folding. | ||
| 338 | ;;; | ||
| 339 | |||
| 340 | (define-condition-type &service-error &error | ||
| 341 | service-error?) | ||
| 342 | |||
| 343 | (define-condition-type &missing-target-service-error &service-error | ||
| 344 | missing-target-service-error? | ||
| 345 | (service missing-target-service-error-service) | ||
| 346 | (target-type missing-target-service-error-target-type)) | ||
| 347 | |||
| 348 | (define-condition-type &ambiguous-target-service-error &service-error | ||
| 349 | ambiguous-target-service-error? | ||
| 350 | (service ambiguous-target-service-error-service) | ||
| 351 | (target-type ambiguous-target-service-error-target-type)) | ||
| 352 | |||
| 353 | (define (service-back-edges services) | ||
| 354 | "Return a procedure that, when passed a <service>, returns the list of | ||
| 355 | <service> objects that depend on it." | ||
| 356 | (define (add-edges service edges) | ||
| 357 | (define (add-edge extension edges) | ||
| 358 | (let ((target-type (service-extension-target extension))) | ||
| 359 | (match (filter (lambda (service) | ||
| 360 | (eq? (service-kind service) target-type)) | ||
| 361 | services) | ||
| 362 | ((target) | ||
| 363 | (vhash-consq target service edges)) | ||
| 364 | (() | ||
| 365 | (raise | ||
| 366 | (condition (&missing-target-service-error | ||
| 367 | (service service) | ||
| 368 | (target-type target-type)) | ||
| 369 | (&message | ||
| 370 | (message | ||
| 371 | (format #f (_ "no target of type '~a' for service ~s") | ||
| 372 | (service-type-name target-type) | ||
| 373 | service)))))) | ||
| 374 | (x | ||
| 375 | (raise | ||
| 376 | (condition (&ambiguous-target-service-error | ||
| 377 | (service service) | ||
| 378 | (target-type target-type)) | ||
| 379 | (&message | ||
| 380 | (message | ||
| 381 | (format #f | ||
| 382 | (_ "more than one target service of type '~a'") | ||
| 383 | (service-type-name target-type)))))))))) | ||
| 384 | |||
| 385 | (fold add-edge edges (service-type-extensions (service-kind service)))) | ||
| 386 | |||
| 387 | (let ((edges (fold add-edges vlist-null services))) | ||
| 388 | (lambda (node) | ||
| 389 | (reverse (vhash-foldq* cons '() node edges))))) | ||
| 390 | |||
| 391 | (define* (fold-services services #:key (target-type boot-service-type)) | ||
| 392 | "Fold SERVICES by propagating their extensions down to the root of type | ||
| 393 | TARGET-TYPE; return the root service adjusted accordingly." | ||
| 394 | (define dependents | ||
| 395 | (service-back-edges services)) | ||
| 396 | |||
| 397 | (define (matching-extension target) | ||
| 398 | (let ((target (service-kind target))) | ||
| 399 | (match-lambda | ||
| 400 | (($ <service-extension> type) | ||
| 401 | (eq? type target))))) | ||
| 402 | |||
| 403 | (define (apply-extension target) | ||
| 404 | (lambda (service) | ||
| 405 | (match (find (matching-extension target) | ||
| 406 | (service-type-extensions (service-kind service))) | ||
| 407 | (($ <service-extension> _ compute) | ||
| 408 | (compute (service-parameters service)))))) | ||
| 409 | |||
| 410 | (match (filter (lambda (service) | ||
| 411 | (eq? (service-kind service) target-type)) | ||
| 412 | services) | ||
| 413 | ((sink) | ||
| 414 | (let loop ((sink sink)) | ||
| 415 | (let* ((dependents (map loop (dependents sink))) | ||
| 416 | (extensions (map (apply-extension sink) dependents)) | ||
| 417 | (extend (service-type-extend (service-kind sink))) | ||
| 418 | (compose (service-type-compose (service-kind sink))) | ||
| 419 | (params (service-parameters sink))) | ||
| 420 | ;; We distinguish COMPOSE and EXTEND because PARAMS typically has a | ||
| 421 | ;; different type than the elements of EXTENSIONS. | ||
| 422 | (if extend | ||
| 423 | (service (service-kind sink) | ||
| 424 | (extend params (compose extensions))) | ||
| 425 | sink)))) | ||
| 426 | (() | ||
| 427 | (raise | ||
| 428 | (condition (&missing-target-service-error | ||
| 429 | (service #f) | ||
| 430 | (target-type target-type)) | ||
| 431 | (&message | ||
| 432 | (message (format #f (_ "service of type '~a' not found") | ||
| 433 | (service-type-name target-type))))))) | ||
| 434 | (x | ||
| 435 | (raise | ||
| 436 | (condition (&ambiguous-target-service-error | ||
| 437 | (service #f) | ||
| 438 | (target-type target-type)) | ||
| 439 | (&message | ||
| 440 | (message | ||
| 441 | (format #f | ||
| 442 | (_ "more than one target service of type '~a'") | ||
| 443 | (service-type-name target-type))))))))) | ||
| 65 | 444 | ||
| 66 | ;;; services.scm ends here. | 445 | ;;; services.scm ends here. |
diff --git a/gnu/services/avahi.scm b/gnu/services/avahi.scm index 929ac2fbb62..b576c395ffd 100644 --- a/gnu/services/avahi.scm +++ b/gnu/services/avahi.scm | |||
| @@ -18,10 +18,13 @@ | |||
| 18 | 18 | ||
| 19 | (define-module (gnu services avahi) | 19 | (define-module (gnu services avahi) |
| 20 | #:use-module (gnu services) | 20 | #:use-module (gnu services) |
| 21 | #:use-module (gnu services base) | ||
| 22 | #:use-module (gnu services dmd) | ||
| 23 | #:use-module (gnu services dbus) | ||
| 21 | #:use-module (gnu system shadow) | 24 | #:use-module (gnu system shadow) |
| 22 | #:use-module (gnu packages avahi) | 25 | #:use-module (gnu packages avahi) |
| 23 | #:use-module (gnu packages admin) | 26 | #:use-module (gnu packages admin) |
| 24 | #:use-module (guix store) | 27 | #:use-module (guix records) |
| 25 | #:use-module (guix gexp) | 28 | #:use-module (guix gexp) |
| 26 | #:export (avahi-service)) | 29 | #:export (avahi-service)) |
| 27 | 30 | ||
| @@ -32,12 +35,27 @@ | |||
| 32 | ;;; | 35 | ;;; |
| 33 | ;;; Code: | 36 | ;;; Code: |
| 34 | 37 | ||
| 35 | (define* (configuration-file #:key host-name publish? | 38 | ;; TODO: Export. |
| 36 | ipv4? ipv6? wide-area? domains-to-browse) | 39 | (define-record-type* <avahi-configuration> |
| 37 | "Return an avahi-daemon configuration file." | 40 | avahi-configuration make-avahi-configuration |
| 41 | avahi-configuration? | ||
| 42 | (avahi avahi-configuration-avahi ;<package> | ||
| 43 | (default avahi)) | ||
| 44 | (host-name avahi-configuration-host-name) ;string | ||
| 45 | (publish? avahi-configuration-publish?) ;Boolean | ||
| 46 | (ipv4? avahi-configuration-ipv4?) ;Boolean | ||
| 47 | (ipv6? avahi-configuration-ipv6?) ;Boolean | ||
| 48 | (wide-area? avahi-configuration-wide-area?) ;Boolean | ||
| 49 | (domains-to-browse avahi-configuration-domains-to-browse)) ;list of strings | ||
| 50 | |||
| 51 | (define* (configuration-file config) | ||
| 52 | "Return an avahi-daemon configuration file based on CONFIG, an | ||
| 53 | <avahi-configuration>." | ||
| 38 | (define (bool value) | 54 | (define (bool value) |
| 39 | (if value "yes\n" "no\n")) | 55 | (if value "yes\n" "no\n")) |
| 40 | 56 | ||
| 57 | (define host-name (avahi-configuration-host-name config)) | ||
| 58 | |||
| 41 | (plain-file "avahi-daemon.conf" | 59 | (plain-file "avahi-daemon.conf" |
| 42 | (string-append | 60 | (string-append |
| 43 | "[server]\n" | 61 | "[server]\n" |
| @@ -45,14 +63,63 @@ | |||
| 45 | (string-append "host-name=" host-name "\n") | 63 | (string-append "host-name=" host-name "\n") |
| 46 | "") | 64 | "") |
| 47 | 65 | ||
| 48 | "browse-domains=" (string-join domains-to-browse) | 66 | "browse-domains=" (string-join |
| 67 | (avahi-configuration-domains-to-browse | ||
| 68 | config)) | ||
| 49 | "\n" | 69 | "\n" |
| 50 | "use-ipv4=" (bool ipv4?) | 70 | "use-ipv4=" (bool (avahi-configuration-ipv4? config)) |
| 51 | "use-ipv6=" (bool ipv6?) | 71 | "use-ipv6=" (bool (avahi-configuration-ipv6? config)) |
| 52 | "[wide-area]\n" | 72 | "[wide-area]\n" |
| 53 | "enable-wide-area=" (bool wide-area?) | 73 | "enable-wide-area=" (bool (avahi-configuration-wide-area? config)) |
| 54 | "[publish]\n" | 74 | "[publish]\n" |
| 55 | "disable-publishing=" (bool (not publish?))))) | 75 | "disable-publishing=" |
| 76 | (bool (not (avahi-configuration-publish? config)))))) | ||
| 77 | |||
| 78 | (define %avahi-accounts | ||
| 79 | ;; Account and group for the Avahi daemon. | ||
| 80 | (list (user-group (name "avahi") (system? #t)) | ||
| 81 | (user-account | ||
| 82 | (name "avahi") | ||
| 83 | (group "avahi") | ||
| 84 | (system? #t) | ||
| 85 | (comment "Avahi daemon user") | ||
| 86 | (home-directory "/var/empty") | ||
| 87 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 88 | |||
| 89 | (define %avahi-activation | ||
| 90 | ;; Activation gexp. | ||
| 91 | #~(begin | ||
| 92 | (use-modules (guix build utils)) | ||
| 93 | (mkdir-p "/var/run/avahi-daemon"))) | ||
| 94 | |||
| 95 | (define (avahi-dmd-service config) | ||
| 96 | "Return a list of <dmd-service> for CONFIG." | ||
| 97 | (let ((config (configuration-file config)) | ||
| 98 | (avahi (avahi-configuration-avahi config))) | ||
| 99 | (list (dmd-service | ||
| 100 | (documentation "Run the Avahi mDNS/DNS-SD responder.") | ||
| 101 | (provision '(avahi-daemon)) | ||
| 102 | (requirement '(dbus-system networking)) | ||
| 103 | |||
| 104 | (start #~(make-forkexec-constructor | ||
| 105 | (list (string-append #$avahi "/sbin/avahi-daemon") | ||
| 106 | "--syslog" "-f" #$config))) | ||
| 107 | (stop #~(make-kill-destructor)))))) | ||
| 108 | |||
| 109 | (define avahi-service-type | ||
| 110 | (service-type (name 'avahi) | ||
| 111 | (extensions | ||
| 112 | (list (service-extension dmd-root-service-type | ||
| 113 | avahi-dmd-service) | ||
| 114 | (service-extension dbus-root-service-type | ||
| 115 | (compose list | ||
| 116 | avahi-configuration-avahi)) | ||
| 117 | (service-extension account-service-type | ||
| 118 | (const %avahi-accounts)) | ||
| 119 | (service-extension activation-service-type | ||
| 120 | (const %avahi-activation)) | ||
| 121 | (service-extension nscd-service-type | ||
| 122 | (const (list nss-mdns))))))) | ||
| 56 | 123 | ||
| 57 | (define* (avahi-service #:key (avahi avahi) | 124 | (define* (avahi-service #:key (avahi avahi) |
| 58 | host-name | 125 | host-name |
| @@ -75,36 +142,11 @@ When @var{wide-area?} is true, DNS-SD over unicast DNS is enabled. | |||
| 75 | 142 | ||
| 76 | Boolean values @var{ipv4?} and @var{ipv6?} determine whether to use IPv4/IPv6 | 143 | Boolean values @var{ipv4?} and @var{ipv6?} determine whether to use IPv4/IPv6 |
| 77 | sockets." | 144 | sockets." |
| 78 | (let ((config (configuration-file #:host-name host-name | 145 | (service avahi-service-type |
| 79 | #:publish? publish? | 146 | (avahi-configuration |
| 80 | #:ipv4? ipv4? | 147 | (avahi avahi) (host-name host-name) |
| 81 | #:ipv6? ipv6? | 148 | (publish? publish?) (ipv4? ipv4?) (ipv6? ipv6?) |
| 82 | #:wide-area? wide-area? | 149 | (wide-area? wide-area?) |
| 83 | #:domains-to-browse | 150 | (domains-to-browse domains-to-browse)))) |
| 84 | domains-to-browse))) | ||
| 85 | (service | ||
| 86 | (documentation "Run the Avahi mDNS/DNS-SD responder.") | ||
| 87 | (provision '(avahi-daemon)) | ||
| 88 | (requirement '(dbus-system networking)) | ||
| 89 | |||
| 90 | (start #~(make-forkexec-constructor | ||
| 91 | (list (string-append #$avahi "/sbin/avahi-daemon") | ||
| 92 | "--syslog" "-f" #$config))) | ||
| 93 | (stop #~(make-kill-destructor)) | ||
| 94 | (activate #~(begin | ||
| 95 | (use-modules (guix build utils)) | ||
| 96 | (mkdir-p "/var/run/avahi-daemon"))) | ||
| 97 | |||
| 98 | (user-groups (list (user-group | ||
| 99 | (name "avahi") | ||
| 100 | (system? #t)))) | ||
| 101 | (user-accounts (list (user-account | ||
| 102 | (name "avahi") | ||
| 103 | (group "avahi") | ||
| 104 | (system? #t) | ||
| 105 | (comment "Avahi daemon user") | ||
| 106 | (home-directory "/var/empty") | ||
| 107 | (shell | ||
| 108 | #~(string-append #$shadow "/sbin/nologin")))))))) | ||
| 109 | 151 | ||
| 110 | ;;; avahi.scm ends here | 152 | ;;; avahi.scm ends here |
diff --git a/gnu/services/base.scm b/gnu/services/base.scm index d9d73b45973..adafe1b55ea 100644 --- a/gnu/services/base.scm +++ b/gnu/services/base.scm | |||
| @@ -21,9 +21,11 @@ | |||
| 21 | (define-module (gnu services base) | 21 | (define-module (gnu services base) |
| 22 | #:use-module (guix store) | 22 | #:use-module (guix store) |
| 23 | #:use-module (gnu services) | 23 | #:use-module (gnu services) |
| 24 | #:use-module (gnu services dmd) | ||
| 24 | #:use-module (gnu services networking) | 25 | #:use-module (gnu services networking) |
| 25 | #:use-module (gnu system shadow) ; 'user-account', etc. | 26 | #:use-module (gnu system shadow) ; 'user-account', etc. |
| 26 | #:use-module (gnu system linux) ; 'pam-service', etc. | 27 | #:use-module (gnu system linux) ; 'pam-service', etc. |
| 28 | #:use-module (gnu system file-systems) ; 'file-system', etc. | ||
| 27 | #:use-module (gnu packages admin) | 29 | #:use-module (gnu packages admin) |
| 28 | #:use-module ((gnu packages linux) | 30 | #:use-module ((gnu packages linux) |
| 29 | #:select (eudev kbd e2fsprogs lvm2 fuse alsa-utils crda)) | 31 | #:select (eudev kbd e2fsprogs lvm2 fuse alsa-utils crda)) |
| @@ -49,6 +51,7 @@ | |||
| 49 | host-name-service | 51 | host-name-service |
| 50 | console-keymap-service | 52 | console-keymap-service |
| 51 | console-font-service | 53 | console-font-service |
| 54 | udev-service-type | ||
| 52 | udev-service | 55 | udev-service |
| 53 | 56 | ||
| 54 | mingetty-configuration | 57 | mingetty-configuration |
| @@ -64,9 +67,14 @@ | |||
| 64 | nscd-cache | 67 | nscd-cache |
| 65 | nscd-cache? | 68 | nscd-cache? |
| 66 | 69 | ||
| 70 | nscd-service-type | ||
| 67 | nscd-service | 71 | nscd-service |
| 68 | syslog-service | 72 | syslog-service |
| 73 | |||
| 74 | guix-configuration | ||
| 75 | guix-configuration? | ||
| 69 | guix-service | 76 | guix-service |
| 77 | |||
| 70 | %base-services)) | 78 | %base-services)) |
| 71 | 79 | ||
| 72 | ;;; Commentary: | 80 | ;;; Commentary: |
| @@ -76,13 +84,13 @@ | |||
| 76 | ;;; | 84 | ;;; |
| 77 | ;;; Code: | 85 | ;;; Code: |
| 78 | 86 | ||
| 79 | (define (root-file-system-service) | 87 | |
| 80 | "Return a service whose sole purpose is to re-mount read-only the root file | 88 | ;;; |
| 81 | system upon shutdown (aka. cleanly \"umounting\" root.) | 89 | ;;; File systems. |
| 90 | ;;; | ||
| 82 | 91 | ||
| 83 | This service must be the root of the service dependency graph so that its | 92 | (define %root-file-system-dmd-service |
| 84 | 'stop' action is invoked when dmd is the only process left." | 93 | (dmd-service |
| 85 | (service | ||
| 86 | (documentation "Take care of the root file system.") | 94 | (documentation "Take care of the root file system.") |
| 87 | (provision '(root-file-system)) | 95 | (provision '(root-file-system)) |
| 88 | (start #~(const #t)) | 96 | (start #~(const #t)) |
| @@ -116,181 +124,230 @@ This service must be the root of the service dependency graph so that its | |||
| 116 | #f))))) | 124 | #f))))) |
| 117 | (respawn? #f))) | 125 | (respawn? #f))) |
| 118 | 126 | ||
| 119 | (define* (file-system-service device target type | 127 | (define root-file-system-service-type |
| 120 | #:key (flags '()) (check? #t) | 128 | (dmd-service-type (const %root-file-system-dmd-service))) |
| 121 | create-mount-point? options (title 'any) | 129 | |
| 122 | (requirements '())) | 130 | (define (root-file-system-service) |
| 123 | "Return a service that mounts DEVICE on TARGET as a file system TYPE with | 131 | "Return a service whose sole purpose is to re-mount read-only the root file |
| 124 | OPTIONS. TITLE is a symbol specifying what kind of name DEVICE is: 'label for | 132 | system upon shutdown (aka. cleanly \"umounting\" root.) |
| 125 | a partition label, 'device for a device file name, or 'any. When CHECK? is | 133 | |
| 126 | true, check the file system before mounting it. When CREATE-MOUNT-POINT? is | 134 | This service must be the root of the service dependency graph so that its |
| 127 | true, create TARGET if it does not exist yet. FLAGS is a list of symbols, | 135 | 'stop' action is invoked when dmd is the only process left." |
| 128 | such as 'read-only' etc. Optionally, REQUIREMENTS may be a list of service | 136 | (service root-file-system-service-type #f)) |
| 129 | names such as device-mapping services." | 137 | |
| 130 | (service | 138 | (define (file-system->dmd-service-name file-system) |
| 131 | (provision (list (symbol-append 'file-system- (string->symbol target)))) | 139 | "Return the symbol that denotes the service mounting and unmounting |
| 132 | (requirement `(root-file-system ,@requirements)) | 140 | FILE-SYSTEM." |
| 133 | (documentation "Check, mount, and unmount the given file system.") | 141 | (symbol-append 'file-system- |
| 134 | (start #~(lambda args | 142 | (string->symbol (file-system-mount-point file-system)))) |
| 135 | ;; FIXME: Use or factorize with 'mount-file-system'. | 143 | |
| 136 | (let ((device (canonicalize-device-spec #$device '#$title)) | 144 | (define file-system-service-type |
| 137 | (flags #$(mount-flags->bit-mask flags))) | 145 | ;; TODO(?): Make this an extensible service that takes <file-system> objects |
| 138 | #$(if create-mount-point? | 146 | ;; and returns a list of <dmd-service>. |
| 139 | #~(mkdir-p #$target) | 147 | (dmd-service-type |
| 140 | #~#t) | 148 | (lambda (file-system) |
| 141 | #$(if check? | 149 | (let ((target (file-system-mount-point file-system)) |
| 142 | #~(begin | 150 | (device (file-system-device file-system)) |
| 143 | ;; Make sure fsck.ext2 & co. can be found. | 151 | (type (file-system-type file-system)) |
| 144 | (setenv "PATH" | 152 | (title (file-system-title file-system)) |
| 145 | (string-append | 153 | (check? (file-system-check? file-system)) |
| 146 | #$e2fsprogs "/sbin:" | 154 | (create? (file-system-create-mount-point? file-system)) |
| 147 | "/run/current-system/profile/sbin:" | 155 | (dependencies (file-system-dependencies file-system))) |
| 148 | (getenv "PATH"))) | 156 | (dmd-service |
| 149 | (check-file-system device #$type)) | 157 | (provision (list (file-system->dmd-service-name file-system))) |
| 150 | #~#t) | 158 | (requirement `(root-file-system |
| 151 | 159 | ,@(map file-system->dmd-service-name dependencies))) | |
| 152 | (mount device #$target #$type flags #$options) | 160 | (documentation "Check, mount, and unmount the given file system.") |
| 153 | 161 | (start #~(lambda args | |
| 154 | ;; For read-only bind mounts, an extra remount is needed, | 162 | ;; FIXME: Use or factorize with 'mount-file-system'. |
| 155 | ;; as per <http://lwn.net/Articles/281157/>, which still | 163 | (let ((device (canonicalize-device-spec #$device '#$title)) |
| 156 | ;; applies to Linux 4.0. | 164 | (flags #$(mount-flags->bit-mask |
| 157 | (when (and (= MS_BIND (logand flags MS_BIND)) | 165 | (file-system-flags file-system)))) |
| 158 | (= MS_RDONLY (logand flags MS_RDONLY))) | 166 | #$(if create? |
| 159 | (mount device #$target #$type | 167 | #~(mkdir-p #$target) |
| 160 | (logior MS_BIND MS_REMOUNT MS_RDONLY)))) | 168 | #~#t) |
| 161 | #t)) | 169 | #$(if check? |
| 162 | (stop #~(lambda args | 170 | #~(begin |
| 163 | ;; Normally there are no processes left at this point, so | 171 | ;; Make sure fsck.ext2 & co. can be found. |
| 164 | ;; TARGET can be safely unmounted. | 172 | (setenv "PATH" |
| 165 | 173 | (string-append | |
| 166 | ;; Make sure PID 1 doesn't keep TARGET busy. | 174 | #$e2fsprogs "/sbin:" |
| 167 | (chdir "/") | 175 | "/run/current-system/profile/sbin:" |
| 168 | 176 | (getenv "PATH"))) | |
| 169 | (umount #$target) | 177 | (check-file-system device #$type)) |
| 170 | #f)))) | 178 | #~#t) |
| 179 | |||
| 180 | (mount device #$target #$type flags | ||
| 181 | #$(file-system-options file-system)) | ||
| 182 | |||
| 183 | ;; For read-only bind mounts, an extra remount is needed, | ||
| 184 | ;; as per <http://lwn.net/Articles/281157/>, which still | ||
| 185 | ;; applies to Linux 4.0. | ||
| 186 | (when (and (= MS_BIND (logand flags MS_BIND)) | ||
| 187 | (= MS_RDONLY (logand flags MS_RDONLY))) | ||
| 188 | (mount device #$target #$type | ||
| 189 | (logior MS_BIND MS_REMOUNT MS_RDONLY)))) | ||
| 190 | #t)) | ||
| 191 | (stop #~(lambda args | ||
| 192 | ;; Normally there are no processes left at this point, so | ||
| 193 | ;; TARGET can be safely unmounted. | ||
| 194 | |||
| 195 | ;; Make sure PID 1 doesn't keep TARGET busy. | ||
| 196 | (chdir "/") | ||
| 197 | |||
| 198 | (umount #$target) | ||
| 199 | #f))))))) | ||
| 200 | |||
| 201 | (define* (file-system-service file-system) | ||
| 202 | "Return a service that mounts @var{file-system}, a @code{<file-system>} | ||
| 203 | object." | ||
| 204 | (service file-system-service-type file-system)) | ||
| 205 | |||
| 206 | (define user-unmount-service-type | ||
| 207 | (dmd-service-type | ||
| 208 | (lambda (known-mount-points) | ||
| 209 | (dmd-service | ||
| 210 | (documentation "Unmount manually-mounted file systems.") | ||
| 211 | (provision '(user-unmount)) | ||
| 212 | (start #~(const #t)) | ||
| 213 | (stop #~(lambda args | ||
| 214 | (define (known? mount-point) | ||
| 215 | (member mount-point | ||
| 216 | (cons* "/proc" "/sys" '#$known-mount-points))) | ||
| 217 | |||
| 218 | ;; Make sure we don't keep the user's mount points busy. | ||
| 219 | (chdir "/") | ||
| 220 | |||
| 221 | (for-each (lambda (mount-point) | ||
| 222 | (format #t "unmounting '~a'...~%" mount-point) | ||
| 223 | (catch 'system-error | ||
| 224 | (lambda () | ||
| 225 | (umount mount-point)) | ||
| 226 | (lambda args | ||
| 227 | (let ((errno (system-error-errno args))) | ||
| 228 | (format #t "failed to unmount '~a': ~a~%" | ||
| 229 | mount-point (strerror errno)))))) | ||
| 230 | (filter (negate known?) (mount-points))) | ||
| 231 | #f)))))) | ||
| 171 | 232 | ||
| 172 | (define (user-unmount-service known-mount-points) | 233 | (define (user-unmount-service known-mount-points) |
| 173 | "Return a service whose sole purpose is to unmount file systems not listed | 234 | "Return a service whose sole purpose is to unmount file systems not listed |
| 174 | in KNOWN-MOUNT-POINTS when it is stopped." | 235 | in KNOWN-MOUNT-POINTS when it is stopped." |
| 175 | (service | 236 | (service user-unmount-service-type known-mount-points)) |
| 176 | (documentation "Unmount manually-mounted file systems.") | ||
| 177 | (provision '(user-unmount)) | ||
| 178 | (start #~(const #t)) | ||
| 179 | (stop #~(lambda args | ||
| 180 | (define (known? mount-point) | ||
| 181 | (member mount-point | ||
| 182 | (cons* "/proc" "/sys" | ||
| 183 | '#$known-mount-points))) | ||
| 184 | |||
| 185 | ;; Make sure we don't keep the user's mount points busy. | ||
| 186 | (chdir "/") | ||
| 187 | |||
| 188 | (for-each (lambda (mount-point) | ||
| 189 | (format #t "unmounting '~a'...~%" mount-point) | ||
| 190 | (catch 'system-error | ||
| 191 | (lambda () | ||
| 192 | (umount mount-point)) | ||
| 193 | (lambda args | ||
| 194 | (let ((errno (system-error-errno args))) | ||
| 195 | (format #t "failed to unmount '~a': ~a~%" | ||
| 196 | mount-point (strerror errno)))))) | ||
| 197 | (filter (negate known?) (mount-points))) | ||
| 198 | #f)))) | ||
| 199 | 237 | ||
| 200 | (define %do-not-kill-file | 238 | (define %do-not-kill-file |
| 201 | ;; Name of the file listing PIDs of processes that must survive when halting | 239 | ;; Name of the file listing PIDs of processes that must survive when halting |
| 202 | ;; the system. Typical example is user-space file systems. | 240 | ;; the system. Typical example is user-space file systems. |
| 203 | "/etc/dmd/do-not-kill") | 241 | "/etc/dmd/do-not-kill") |
| 204 | 242 | ||
| 205 | (define* (user-processes-service requirements #:key (grace-delay 4)) | 243 | (define user-processes-service-type |
| 244 | (dmd-service-type | ||
| 245 | (match-lambda | ||
| 246 | ((requirements grace-delay) | ||
| 247 | (dmd-service | ||
| 248 | (documentation "When stopped, terminate all user processes.") | ||
| 249 | (provision '(user-processes)) | ||
| 250 | (requirement (cons 'root-file-system | ||
| 251 | (map file-system->dmd-service-name | ||
| 252 | requirements))) | ||
| 253 | (start #~(const #t)) | ||
| 254 | (stop #~(lambda _ | ||
| 255 | (define (kill-except omit signal) | ||
| 256 | ;; Kill all the processes with SIGNAL except those listed | ||
| 257 | ;; in OMIT and the current process. | ||
| 258 | (let ((omit (cons (getpid) omit))) | ||
| 259 | (for-each (lambda (pid) | ||
| 260 | (unless (memv pid omit) | ||
| 261 | (false-if-exception | ||
| 262 | (kill pid signal)))) | ||
| 263 | (processes)))) | ||
| 264 | |||
| 265 | (define omitted-pids | ||
| 266 | ;; List of PIDs that must not be killed. | ||
| 267 | (if (file-exists? #$%do-not-kill-file) | ||
| 268 | (map string->number | ||
| 269 | (call-with-input-file #$%do-not-kill-file | ||
| 270 | (compose string-tokenize | ||
| 271 | (@ (ice-9 rdelim) read-string)))) | ||
| 272 | '())) | ||
| 273 | |||
| 274 | (define (now) | ||
| 275 | (car (gettimeofday))) | ||
| 276 | |||
| 277 | (define (sleep* n) | ||
| 278 | ;; Really sleep N seconds. | ||
| 279 | ;; Work around <http://bugs.gnu.org/19581>. | ||
| 280 | (define start (now)) | ||
| 281 | (let loop ((elapsed 0)) | ||
| 282 | (when (> n elapsed) | ||
| 283 | (sleep (- n elapsed)) | ||
| 284 | (loop (- (now) start))))) | ||
| 285 | |||
| 286 | (define lset= (@ (srfi srfi-1) lset=)) | ||
| 287 | |||
| 288 | (display "sending all processes the TERM signal\n") | ||
| 289 | |||
| 290 | (if (null? omitted-pids) | ||
| 291 | (begin | ||
| 292 | ;; Easy: terminate all of them. | ||
| 293 | (kill -1 SIGTERM) | ||
| 294 | (sleep* #$grace-delay) | ||
| 295 | (kill -1 SIGKILL)) | ||
| 296 | (begin | ||
| 297 | ;; Kill them all except OMITTED-PIDS. XXX: We would | ||
| 298 | ;; like to (kill -1 SIGSTOP) to get a fixed list of | ||
| 299 | ;; processes, like 'killall5' does, but that seems | ||
| 300 | ;; unreliable. | ||
| 301 | (kill-except omitted-pids SIGTERM) | ||
| 302 | (sleep* #$grace-delay) | ||
| 303 | (kill-except omitted-pids SIGKILL) | ||
| 304 | (delete-file #$%do-not-kill-file))) | ||
| 305 | |||
| 306 | (let wait () | ||
| 307 | (let ((pids (processes))) | ||
| 308 | (unless (lset= = pids (cons 1 omitted-pids)) | ||
| 309 | (format #t "waiting for process termination\ | ||
| 310 | (processes left: ~s)~%" | ||
| 311 | pids) | ||
| 312 | (sleep* 2) | ||
| 313 | (wait)))) | ||
| 314 | |||
| 315 | (display "all processes have been terminated\n") | ||
| 316 | #f)) | ||
| 317 | (respawn? #f)))))) | ||
| 318 | |||
| 319 | (define* (user-processes-service file-systems #:key (grace-delay 4)) | ||
| 206 | "Return the service that is responsible for terminating all the processes so | 320 | "Return the service that is responsible for terminating all the processes so |
| 207 | that the root file system can be re-mounted read-only, just before | 321 | that the root file system can be re-mounted read-only, just before |
| 208 | rebooting/halting. Processes still running GRACE-DELAY seconds after SIGTERM | 322 | rebooting/halting. Processes still running GRACE-DELAY seconds after SIGTERM |
| 209 | has been sent are terminated with SIGKILL. | 323 | has been sent are terminated with SIGKILL. |
| 210 | 324 | ||
| 211 | The returned service will depend on 'root-file-system' and on all the services | 325 | The returned service will depend on 'root-file-system' and on all the dmd |
| 212 | listed in REQUIREMENTS. | 326 | services corresponding to FILE-SYSTEMS. |
| 213 | 327 | ||
| 214 | All the services that spawn processes must depend on this one so that they are | 328 | All the services that spawn processes must depend on this one so that they are |
| 215 | stopped before 'kill' is called." | 329 | stopped before 'kill' is called." |
| 216 | (service | 330 | (service user-processes-service-type |
| 217 | (documentation "When stopped, terminate all user processes.") | 331 | (list file-systems grace-delay))) |
| 218 | (provision '(user-processes)) | ||
| 219 | (requirement (cons 'root-file-system requirements)) | ||
| 220 | (start #~(const #t)) | ||
| 221 | (stop #~(lambda _ | ||
| 222 | (define (kill-except omit signal) | ||
| 223 | ;; Kill all the processes with SIGNAL except those | ||
| 224 | ;; listed in OMIT and the current process. | ||
| 225 | (let ((omit (cons (getpid) omit))) | ||
| 226 | (for-each (lambda (pid) | ||
| 227 | (unless (memv pid omit) | ||
| 228 | (false-if-exception | ||
| 229 | (kill pid signal)))) | ||
| 230 | (processes)))) | ||
| 231 | |||
| 232 | (define omitted-pids | ||
| 233 | ;; List of PIDs that must not be killed. | ||
| 234 | (if (file-exists? #$%do-not-kill-file) | ||
| 235 | (map string->number | ||
| 236 | (call-with-input-file #$%do-not-kill-file | ||
| 237 | (compose string-tokenize | ||
| 238 | (@ (ice-9 rdelim) read-string)))) | ||
| 239 | '())) | ||
| 240 | |||
| 241 | (define (now) | ||
| 242 | (car (gettimeofday))) | ||
| 243 | |||
| 244 | (define (sleep* n) | ||
| 245 | ;; Really sleep N seconds. | ||
| 246 | ;; Work around <http://bugs.gnu.org/19581>. | ||
| 247 | (define start (now)) | ||
| 248 | (let loop ((elapsed 0)) | ||
| 249 | (when (> n elapsed) | ||
| 250 | (sleep (- n elapsed)) | ||
| 251 | (loop (- (now) start))))) | ||
| 252 | |||
| 253 | (define lset= (@ (srfi srfi-1) lset=)) | ||
| 254 | |||
| 255 | (display "sending all processes the TERM signal\n") | ||
| 256 | |||
| 257 | (if (null? omitted-pids) | ||
| 258 | (begin | ||
| 259 | ;; Easy: terminate all of them. | ||
| 260 | (kill -1 SIGTERM) | ||
| 261 | (sleep* #$grace-delay) | ||
| 262 | (kill -1 SIGKILL)) | ||
| 263 | (begin | ||
| 264 | ;; Kill them all except OMITTED-PIDS. XXX: We | ||
| 265 | ;; would like to (kill -1 SIGSTOP) to get a fixed | ||
| 266 | ;; list of processes, like 'killall5' does, but | ||
| 267 | ;; that seems unreliable. | ||
| 268 | (kill-except omitted-pids SIGTERM) | ||
| 269 | (sleep* #$grace-delay) | ||
| 270 | (kill-except omitted-pids SIGKILL) | ||
| 271 | (delete-file #$%do-not-kill-file))) | ||
| 272 | |||
| 273 | (let wait () | ||
| 274 | (let ((pids (processes))) | ||
| 275 | (unless (lset= = pids (cons 1 omitted-pids)) | ||
| 276 | (format #t "waiting for process termination\ | ||
| 277 | (processes left: ~s)~%" | ||
| 278 | pids) | ||
| 279 | (sleep* 2) | ||
| 280 | (wait)))) | ||
| 281 | 332 | ||
| 282 | (display "all processes have been terminated\n") | 333 | |
| 283 | #f)) | 334 | ;;; |
| 284 | (respawn? #f))) | 335 | ;;; Console & co. |
| 336 | ;;; | ||
| 337 | |||
| 338 | (define host-name-service-type | ||
| 339 | (dmd-service-type | ||
| 340 | (lambda (name) | ||
| 341 | (dmd-service | ||
| 342 | (documentation "Initialize the machine's host name.") | ||
| 343 | (provision '(host-name)) | ||
| 344 | (start #~(lambda _ | ||
| 345 | (sethostname #$name))) | ||
| 346 | (respawn? #f))))) | ||
| 285 | 347 | ||
| 286 | (define (host-name-service name) | 348 | (define (host-name-service name) |
| 287 | "Return a service that sets the host name to @var{name}." | 349 | "Return a service that sets the host name to @var{name}." |
| 288 | (service | 350 | (service host-name-service-type name)) |
| 289 | (documentation "Initialize the machine's host name.") | ||
| 290 | (provision '(host-name)) | ||
| 291 | (start #~(lambda _ | ||
| 292 | (sethostname #$name))) | ||
| 293 | (respawn? #f))) | ||
| 294 | 351 | ||
| 295 | (define (unicode-start tty) | 352 | (define (unicode-start tty) |
| 296 | "Return a gexp to start Unicode support on @var{tty}." | 353 | "Return a gexp to start Unicode support on @var{tty}." |
| @@ -310,15 +367,43 @@ stopped before 'kill' is called." | |||
| 310 | (else | 367 | (else |
| 311 | (zero? (cdr (waitpid pid)))))))) | 368 | (zero? (cdr (waitpid pid)))))))) |
| 312 | 369 | ||
| 370 | (define console-keymap-service-type | ||
| 371 | (dmd-service-type | ||
| 372 | (lambda (file) | ||
| 373 | (dmd-service | ||
| 374 | (documentation (string-append "Load console keymap (loadkeys).")) | ||
| 375 | (provision '(console-keymap)) | ||
| 376 | (start #~(lambda _ | ||
| 377 | (zero? (system* (string-append #$kbd "/bin/loadkeys") | ||
| 378 | #$file)))) | ||
| 379 | (respawn? #f))))) | ||
| 380 | |||
| 313 | (define (console-keymap-service file) | 381 | (define (console-keymap-service file) |
| 314 | "Return a service to load console keymap from @var{file}." | 382 | "Return a service to load console keymap from @var{file}." |
| 315 | (service | 383 | (service console-keymap-service-type file)) |
| 316 | (documentation (string-append "Load console keymap (loadkeys).")) | 384 | |
| 317 | (provision '(console-keymap)) | 385 | (define console-font-service-type |
| 318 | (start #~(lambda _ | 386 | (dmd-service-type |
| 319 | (zero? (system* (string-append #$kbd "/bin/loadkeys") | 387 | (match-lambda |
| 320 | #$file)))) | 388 | ((tty font) |
| 321 | (respawn? #f))) | 389 | (let ((device (string-append "/dev/" tty))) |
| 390 | (dmd-service | ||
| 391 | (documentation "Load a Unicode console font.") | ||
| 392 | (provision (list (symbol-append 'console-font- | ||
| 393 | (string->symbol tty)))) | ||
| 394 | |||
| 395 | ;; Start after mingetty has been started on TTY, otherwise the settings | ||
| 396 | ;; are ignored. | ||
| 397 | (requirement (list (symbol-append 'term- | ||
| 398 | (string->symbol tty)))) | ||
| 399 | |||
| 400 | (start #~(lambda _ | ||
| 401 | (and #$(unicode-start device) | ||
| 402 | (zero? | ||
| 403 | (system* (string-append #$kbd "/bin/setfont") | ||
| 404 | "-C" #$device #$font))))) | ||
| 405 | (stop #~(const #t)) | ||
| 406 | (respawn? #f))))))) | ||
| 322 | 407 | ||
| 323 | (define* (console-font-service tty #:optional (font "LatGrkCyr-8x16")) | 408 | (define* (console-font-service tty #:optional (font "LatGrkCyr-8x16")) |
| 324 | "Return a service that sets up Unicode support in @var{tty} and loads | 409 | "Return a service that sets up Unicode support in @var{tty} and loads |
| @@ -326,24 +411,7 @@ stopped before 'kill' is called." | |||
| 326 | ;; Note: 'LatGrkCyr-8x16' has the advantage of providing three common | 411 | ;; Note: 'LatGrkCyr-8x16' has the advantage of providing three common |
| 327 | ;; scripts as well as glyphs for em dash, quotation marks, and other Unicode | 412 | ;; scripts as well as glyphs for em dash, quotation marks, and other Unicode |
| 328 | ;; codepoints notably found in the UTF-8 manual. | 413 | ;; codepoints notably found in the UTF-8 manual. |
| 329 | (let ((device (string-append "/dev/" tty))) | 414 | (service console-font-service-type (list tty font))) |
| 330 | (service | ||
| 331 | (documentation "Load a Unicode console font.") | ||
| 332 | (provision (list (symbol-append 'console-font- | ||
| 333 | (string->symbol tty)))) | ||
| 334 | |||
| 335 | ;; Start after mingetty has been started on TTY, otherwise the | ||
| 336 | ;; settings are ignored. | ||
| 337 | (requirement (list (symbol-append 'term- | ||
| 338 | (string->symbol tty)))) | ||
| 339 | |||
| 340 | (start #~(lambda _ | ||
| 341 | (and #$(unicode-start device) | ||
| 342 | (zero? | ||
| 343 | (system* (string-append #$kbd "/bin/setfont") | ||
| 344 | "-C" #$device #$font))))) | ||
| 345 | (stop #~(const #t)) | ||
| 346 | (respawn? #f)))) | ||
| 347 | 415 | ||
| 348 | (define-record-type* <mingetty-configuration> | 416 | (define-record-type* <mingetty-configuration> |
| 349 | mingetty-configuration make-mingetty-configuration | 417 | mingetty-configuration make-mingetty-configuration |
| @@ -365,43 +433,56 @@ stopped before 'kill' is called." | |||
| 365 | (allow-empty-passwords? mingetty-configuration-allow-empty-passwords? | 433 | (allow-empty-passwords? mingetty-configuration-allow-empty-passwords? |
| 366 | (default #t))) ;Boolean | 434 | (default #t))) ;Boolean |
| 367 | 435 | ||
| 368 | (define* (mingetty-service config) | 436 | (define (mingetty-pam-service conf) |
| 369 | "Return a service to run mingetty according to @var{config}, a | 437 | "Return the list of PAM service needed for CONF." |
| 370 | @code{<mingetty-configuration>} object, which specifies the tty to run, among | 438 | ;; Let 'login' be known to PAM. All the mingetty services will have that |
| 371 | other things." | 439 | ;; PAM service, but that's fine because they're all identical and duplicates |
| 372 | (match config | 440 | ;; are removed. |
| 441 | (list (unix-pam-service "login" | ||
| 442 | #:allow-empty-passwords? | ||
| 443 | (mingetty-configuration-allow-empty-passwords? conf) | ||
| 444 | #:motd | ||
| 445 | (mingetty-configuration-motd conf)))) | ||
| 446 | |||
| 447 | (define mingetty-dmd-service | ||
| 448 | (match-lambda | ||
| 373 | (($ <mingetty-configuration> mingetty tty motd auto-login login-program | 449 | (($ <mingetty-configuration> mingetty tty motd auto-login login-program |
| 374 | login-pause? allow-empty-passwords?) | 450 | login-pause? allow-empty-passwords?) |
| 375 | (service | 451 | (list |
| 376 | (documentation "Run mingetty on an tty.") | 452 | (dmd-service |
| 377 | (provision (list (symbol-append 'term- (string->symbol tty)))) | 453 | (documentation "Run mingetty on an tty.") |
| 378 | 454 | (provision (list (symbol-append 'term- (string->symbol tty)))) | |
| 379 | ;; Since the login prompt shows the host name, wait for the 'host-name' | 455 | |
| 380 | ;; service to be done. Also wait for udev essentially so that the tty | 456 | ;; Since the login prompt shows the host name, wait for the 'host-name' |
| 381 | ;; text is not lost in the middle of kernel messages (XXX). | 457 | ;; service to be done. Also wait for udev essentially so that the tty |
| 382 | (requirement '(user-processes host-name udev)) | 458 | ;; text is not lost in the middle of kernel messages (XXX). |
| 383 | 459 | (requirement '(user-processes host-name udev)) | |
| 384 | (start #~(make-forkexec-constructor | 460 | |
| 385 | (list (string-append #$mingetty "/sbin/mingetty") | 461 | (start #~(make-forkexec-constructor |
| 386 | "--noclear" #$tty | 462 | (list (string-append #$mingetty "/sbin/mingetty") |
| 387 | #$@(if auto-login | 463 | "--noclear" #$tty |
| 388 | #~("--autologin" #$auto-login) | 464 | #$@(if auto-login |
| 389 | #~()) | 465 | #~("--autologin" #$auto-login) |
| 390 | #$@(if login-program | 466 | #~()) |
| 391 | #~("--loginprog" #$login-program) | 467 | #$@(if login-program |
| 392 | #~()) | 468 | #~("--loginprog" #$login-program) |
| 393 | #$@(if login-pause? | 469 | #~()) |
| 394 | #~("--loginpause") | 470 | #$@(if login-pause? |
| 395 | #~())))) | 471 | #~("--loginpause") |
| 396 | (stop #~(make-kill-destructor)) | 472 | #~())))) |
| 397 | 473 | (stop #~(make-kill-destructor))))))) | |
| 398 | (pam-services | 474 | |
| 399 | ;; Let 'login' be known to PAM. All the mingetty services will have | 475 | (define mingetty-service-type |
| 400 | ;; that PAM service, but that's fine because they're all identical and | 476 | (service-type (name 'mingetty) |
| 401 | ;; duplicates are removed. | 477 | (extensions (list (service-extension dmd-root-service-type |
| 402 | (list (unix-pam-service "login" | 478 | mingetty-dmd-service) |
| 403 | #:allow-empty-passwords? allow-empty-passwords? | 479 | (service-extension pam-root-service-type |
| 404 | #:motd motd))))))) | 480 | mingetty-pam-service))))) |
| 481 | |||
| 482 | (define* (mingetty-service config) | ||
| 483 | "Return a service to run mingetty according to @var{config}, which specifies | ||
| 484 | the tty to run, among other things." | ||
| 485 | (service mingetty-service-type config)) | ||
| 405 | 486 | ||
| 406 | (define-record-type* <nscd-configuration> nscd-configuration | 487 | (define-record-type* <nscd-configuration> nscd-configuration |
| 407 | make-nscd-configuration | 488 | make-nscd-configuration |
| @@ -506,38 +587,72 @@ other things." | |||
| 506 | (string-concatenate | 587 | (string-concatenate |
| 507 | (map cache->config caches))))))) | 588 | (map cache->config caches))))))) |
| 508 | 589 | ||
| 590 | (define (nscd-dmd-service config) | ||
| 591 | "Return a dmd service for CONFIG, an <nscd-configuration> object." | ||
| 592 | (let ((nscd.conf (nscd.conf-file config)) | ||
| 593 | (name-services (nscd-configuration-name-services config))) | ||
| 594 | (list (dmd-service | ||
| 595 | (documentation "Run libc's name service cache daemon (nscd).") | ||
| 596 | (provision '(nscd)) | ||
| 597 | (requirement '(user-processes)) | ||
| 598 | (start #~(make-forkexec-constructor | ||
| 599 | (list (string-append #$(nscd-configuration-glibc config) | ||
| 600 | "/sbin/nscd") | ||
| 601 | "-f" #$nscd.conf "--foreground") | ||
| 602 | |||
| 603 | #:environment-variables | ||
| 604 | (list (string-append "LD_LIBRARY_PATH=" | ||
| 605 | (string-join | ||
| 606 | (map (lambda (dir) | ||
| 607 | (string-append dir "/lib")) | ||
| 608 | (list #$@name-services)) | ||
| 609 | ":"))))) | ||
| 610 | (stop #~(make-kill-destructor)) | ||
| 611 | |||
| 612 | (respawn? #f))))) | ||
| 613 | |||
| 614 | (define nscd-activation | ||
| 615 | ;; Actions to take before starting nscd. | ||
| 616 | #~(begin | ||
| 617 | (use-modules (guix build utils)) | ||
| 618 | (mkdir-p "/var/run/nscd") | ||
| 619 | (mkdir-p "/var/db/nscd"))) ;for the persistent cache | ||
| 620 | |||
| 621 | (define nscd-service-type | ||
| 622 | (service-type (name 'nscd) | ||
| 623 | (extensions | ||
| 624 | (list (service-extension activation-service-type | ||
| 625 | (const nscd-activation)) | ||
| 626 | (service-extension dmd-root-service-type | ||
| 627 | nscd-dmd-service))) | ||
| 628 | |||
| 629 | ;; This can be extended by providing additional name services | ||
| 630 | ;; such as nss-mdns. | ||
| 631 | (compose concatenate) | ||
| 632 | (extend (lambda (config name-services) | ||
| 633 | (nscd-configuration | ||
| 634 | (inherit config) | ||
| 635 | (name-services (append | ||
| 636 | (nscd-configuration-name-services config) | ||
| 637 | name-services))))))) | ||
| 638 | |||
| 509 | (define* (nscd-service #:optional (config %nscd-default-configuration)) | 639 | (define* (nscd-service #:optional (config %nscd-default-configuration)) |
| 510 | "Return a service that runs libc's name service cache daemon (nscd) with the | 640 | "Return a service that runs libc's name service cache daemon (nscd) with the |
| 511 | given @var{config}---an @code{<nscd-configuration>} object. @xref{Name | 641 | given @var{config}---an @code{<nscd-configuration>} object. @xref{Name |
| 512 | Service Switch}, for an example." | 642 | Service Switch}, for an example." |
| 513 | (let ((nscd.conf (nscd.conf-file config))) | 643 | (service nscd-service-type config)) |
| 514 | (service | 644 | |
| 515 | (documentation "Run libc's name service cache daemon (nscd).") | 645 | (define syslog-service-type |
| 516 | (provision '(nscd)) | 646 | (dmd-service-type |
| 517 | (requirement '(user-processes)) | 647 | (lambda (config-file) |
| 518 | 648 | (dmd-service | |
| 519 | (activate #~(begin | 649 | (documentation "Run the syslog daemon (syslogd).") |
| 520 | (use-modules (guix build utils)) | 650 | (provision '(syslogd)) |
| 521 | (mkdir-p "/var/run/nscd") | 651 | (requirement '(user-processes)) |
| 522 | (mkdir-p "/var/db/nscd"))) ;for the persistent cache | 652 | (start #~(make-forkexec-constructor |
| 523 | 653 | (list (string-append #$inetutils "/libexec/syslogd") | |
| 524 | (start #~(make-forkexec-constructor | 654 | "--no-detach" "--rcfile" #$config-file))) |
| 525 | (list (string-append #$(nscd-configuration-glibc config) | 655 | (stop #~(make-kill-destructor)))))) |
| 526 | "/sbin/nscd") | ||
| 527 | "-f" #$nscd.conf "--foreground") | ||
| 528 | |||
| 529 | #:environment-variables | ||
| 530 | (list (string-append "LD_LIBRARY_PATH=" | ||
| 531 | (string-join | ||
| 532 | (map (lambda (dir) | ||
| 533 | (string-append dir "/lib")) | ||
| 534 | (list | ||
| 535 | #$@(nscd-configuration-name-services | ||
| 536 | config))) | ||
| 537 | ":"))))) | ||
| 538 | (stop #~(make-kill-destructor)) | ||
| 539 | |||
| 540 | (respawn? #f)))) | ||
| 541 | 656 | ||
| 542 | ;; Snippet adapted from the GNU inetutils manual. | 657 | ;; Snippet adapted from the GNU inetutils manual. |
| 543 | (define %default-syslog.conf | 658 | (define %default-syslog.conf |
| @@ -561,18 +676,12 @@ Service Switch}, for an example." | |||
| 561 | # Log all the mail messages in one place. | 676 | # Log all the mail messages in one place. |
| 562 | mail.* /var/log/maillog | 677 | mail.* /var/log/maillog |
| 563 | ")) | 678 | ")) |
| 679 | |||
| 564 | (define* (syslog-service #:key (config-file %default-syslog.conf)) | 680 | (define* (syslog-service #:key (config-file %default-syslog.conf)) |
| 565 | "Return a service that runs @code{syslogd}. | 681 | "Return a service that runs @code{syslogd}. |
| 566 | If configuration file name @var{config-file} is not specified, use some | 682 | If configuration file name @var{config-file} is not specified, use some |
| 567 | reasonable default settings." | 683 | reasonable default settings." |
| 568 | (service | 684 | (service syslog-service-type config-file)) |
| 569 | (documentation "Run the syslog daemon (syslogd).") | ||
| 570 | (provision '(syslogd)) | ||
| 571 | (requirement '(user-processes)) | ||
| 572 | (start #~(make-forkexec-constructor | ||
| 573 | (list (string-append #$inetutils "/libexec/syslogd") | ||
| 574 | "--no-detach" "--rcfile" #$config-file))) | ||
| 575 | (stop #~(make-kill-destructor)))) | ||
| 576 | 685 | ||
| 577 | (define* (guix-build-accounts count #:key | 686 | (define* (guix-build-accounts count #:key |
| 578 | (group "guixbuild") | 687 | (group "guixbuild") |
| @@ -621,61 +730,104 @@ GUIX." | |||
| 621 | (format (current-error-port) "warning: \ | 730 | (format (current-error-port) "warning: \ |
| 622 | failed to register hydra.gnu.org public key: ~a~%" status)))))))) | 731 | failed to register hydra.gnu.org public key: ~a~%" status)))))))) |
| 623 | 732 | ||
| 624 | (define* (guix-service #:key (guix guix) (builder-group "guixbuild") | 733 | (define-record-type* <guix-configuration> |
| 625 | (build-accounts 10) (authorize-hydra-key? #t) | 734 | guix-configuration make-guix-configuration |
| 626 | (use-substitutes? #t) | 735 | guix-configuration? |
| 627 | (extra-options '()) | 736 | (guix guix-configuration-guix ;<package> |
| 628 | (lsof lsof) (lsh lsh)) | 737 | (default guix)) |
| 629 | "Return a service that runs the build daemon from @var{guix}, and has | 738 | (build-group guix-configuration-build-group ;string |
| 630 | @var{build-accounts} user accounts available under @var{builder-group}. | 739 | (default "guixbuild")) |
| 631 | 740 | (build-accounts guix-configuration-build-accounts ;integer | |
| 632 | When @var{authorize-hydra-key?} is true, the @code{hydra.gnu.org} public key | 741 | (default 10)) |
| 633 | provided by @var{guix} is authorized upon activation, meaning that substitutes | 742 | (authorize-key? guix-configuration-authorize-key? ;Boolean |
| 634 | from @code{hydra.gnu.org} are used by default. | 743 | (default #t)) |
| 635 | 744 | (use-substitutes? guix-configuration-use-substitutes? ;Boolean | |
| 636 | If @var{use-substitutes?} is false, the daemon is run with | 745 | (default #t)) |
| 637 | @option{--no-substitutes} (@pxref{Invoking guix-daemon, | 746 | (extra-options guix-configuration-extra-options ;list of strings |
| 638 | @option{--no-substitutes}}). | 747 | (default '())) |
| 639 | 748 | (lsof guix-configuration-lsof ;<package> | |
| 640 | Finally, @var{extra-options} is a list of additional command-line options | 749 | (default lsof)) |
| 641 | passed to @command{guix-daemon}." | 750 | (lsh guix-configuration-lsh ;<package> |
| 642 | (define activate | 751 | (default lsh))) |
| 643 | ;; Assume that the store has BUILDER-GROUP as its group. We could | 752 | |
| 644 | ;; otherwise call 'chown' here, but the problem is that on a COW unionfs, | 753 | (define %default-guix-configuration |
| 645 | ;; chown leads to an entire copy of the tree, which is a bad idea. | 754 | (guix-configuration)) |
| 646 | 755 | ||
| 647 | ;; Optionally authorize hydra.gnu.org's key. | 756 | (define (guix-dmd-service config) |
| 648 | (and authorize-hydra-key? | 757 | "Return a <dmd-service> for the Guix daemon service with CONFIG." |
| 649 | (hydra-key-authorization guix))) | 758 | (match config |
| 650 | 759 | (($ <guix-configuration> guix build-group build-accounts authorize-key? | |
| 651 | (service | 760 | use-substitutes? extra-options lsof lsh) |
| 652 | (documentation "Run the Guix daemon.") | 761 | (list (dmd-service |
| 653 | (provision '(guix-daemon)) | 762 | (documentation "Run the Guix daemon.") |
| 654 | (requirement '(user-processes)) | 763 | (provision '(guix-daemon)) |
| 655 | (start | 764 | (requirement '(user-processes)) |
| 656 | #~(make-forkexec-constructor | 765 | (start |
| 657 | (list (string-append #$guix "/bin/guix-daemon") | 766 | #~(make-forkexec-constructor |
| 658 | "--build-users-group" #$builder-group | 767 | (list (string-append #$guix "/bin/guix-daemon") |
| 659 | #$@(if use-substitutes? | 768 | "--build-users-group" #$build-group |
| 660 | '() | 769 | #$@(if use-substitutes? |
| 661 | '("--no-substitutes")) | 770 | '() |
| 662 | #$@extra-options) | 771 | '("--no-substitutes")) |
| 663 | 772 | #$@extra-options) | |
| 664 | ;; Add 'lsof' (for the GC) and 'lsh' (for offloading) to the | 773 | |
| 665 | ;; daemon's $PATH. | 774 | ;; Add 'lsof' (for the GC) and 'lsh' (for offloading) to the |
| 666 | #:environment-variables | 775 | ;; daemon's $PATH. |
| 667 | (list (string-append "PATH=" #$lsof "/bin:" #$lsh "/bin")))) | 776 | #:environment-variables |
| 668 | (stop #~(make-kill-destructor)) | 777 | (list (string-append "PATH=" #$lsof "/bin:" #$lsh "/bin")))) |
| 669 | (user-accounts (guix-build-accounts build-accounts | 778 | (stop #~(make-kill-destructor))))))) |
| 670 | #:group builder-group)) | 779 | |
| 671 | (user-groups (list (user-group | 780 | (define (guix-accounts config) |
| 672 | (name builder-group) | 781 | "Return the user accounts and user groups for CONFIG." |
| 673 | (system? #t) | 782 | (match config |
| 674 | 783 | (($ <guix-configuration> _ build-group build-accounts) | |
| 675 | ;; Use a fixed GID so that we can create the | 784 | (cons (user-group |
| 676 | ;; store with the right owner. | 785 | (name build-group) |
| 677 | (id 30000)))) | 786 | (system? #t) |
| 678 | (activate activate))) | 787 | |
| 788 | ;; Use a fixed GID so that we can create the store with the right | ||
| 789 | ;; owner. | ||
| 790 | (id 30000)) | ||
| 791 | (guix-build-accounts build-accounts | ||
| 792 | #:group build-group))))) | ||
| 793 | |||
| 794 | (define (guix-activation config) | ||
| 795 | "Return the activation gexp for CONFIG." | ||
| 796 | (match config | ||
| 797 | (($ <guix-configuration> guix build-group build-accounts authorize-key?) | ||
| 798 | ;; Assume that the store has BUILD-GROUP as its group. We could | ||
| 799 | ;; otherwise call 'chown' here, but the problem is that on a COW unionfs, | ||
| 800 | ;; chown leads to an entire copy of the tree, which is a bad idea. | ||
| 801 | |||
| 802 | ;; Optionally authorize hydra.gnu.org's key. | ||
| 803 | (and authorize-key? | ||
| 804 | (hydra-key-authorization guix))))) | ||
| 805 | |||
| 806 | (define guix-service-type | ||
| 807 | (service-type | ||
| 808 | (name 'guix) | ||
| 809 | (extensions | ||
| 810 | (list (service-extension dmd-root-service-type guix-dmd-service) | ||
| 811 | (service-extension account-service-type guix-accounts) | ||
| 812 | (service-extension activation-service-type guix-activation))))) | ||
| 813 | |||
| 814 | (define* (guix-service #:optional (config %default-guix-configuration)) | ||
| 815 | "Return a service that runs the Guix build daemon according to | ||
| 816 | @var{config}." | ||
| 817 | (service guix-service-type config)) | ||
| 818 | |||
| 819 | |||
| 820 | ;;; | ||
| 821 | ;;; Udev. | ||
| 822 | ;;; | ||
| 823 | |||
| 824 | (define-record-type* <udev-configuration> | ||
| 825 | udev-configuration make-udev-configuration | ||
| 826 | udev-configuration? | ||
| 827 | (udev udev-configuration-udev ;<package> | ||
| 828 | (default udev)) | ||
| 829 | (rules udev-configuration-rules ;list of <package> | ||
| 830 | (default '()))) | ||
| 679 | 831 | ||
| 680 | (define (udev-rules-union packages) | 832 | (define (udev-rules-union packages) |
| 681 | "Return the union of the @code{lib/udev/rules.d} directories found in each | 833 | "Return the union of the @code{lib/udev/rules.d} directories found in each |
| @@ -727,118 +879,150 @@ item of @var{packages}." | |||
| 727 | KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0660\"\n" port)))) | 879 | KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0660\"\n" port)))) |
| 728 | #:modules '((guix build utils)))) | 880 | #:modules '((guix build utils)))) |
| 729 | 881 | ||
| 882 | (define udev-dmd-service | ||
| 883 | ;; Return a <dmd-service> for UDEV with RULES. | ||
| 884 | (match-lambda | ||
| 885 | (($ <udev-configuration> udev rules) | ||
| 886 | (let* ((rules (udev-rules-union (cons* udev (kvm-udev-rule) rules))) | ||
| 887 | (udev.conf (computed-file "udev.conf" | ||
| 888 | #~(call-with-output-file #$output | ||
| 889 | (lambda (port) | ||
| 890 | (format port | ||
| 891 | "udev_rules=\"~a/lib/udev/rules.d\"\n" | ||
| 892 | #$rules)))))) | ||
| 893 | (list | ||
| 894 | (dmd-service | ||
| 895 | (provision '(udev)) | ||
| 896 | |||
| 897 | ;; Udev needs /dev to be a 'devtmpfs' mount so that new device nodes can | ||
| 898 | ;; be added: see | ||
| 899 | ;; <http://www.linuxfromscratch.org/lfs/view/development/chapter07/udev.html>. | ||
| 900 | (requirement '(root-file-system)) | ||
| 901 | |||
| 902 | (documentation "Populate the /dev directory, dynamically.") | ||
| 903 | (start #~(lambda () | ||
| 904 | (define find | ||
| 905 | (@ (srfi srfi-1) find)) | ||
| 906 | |||
| 907 | (define udevd | ||
| 908 | ;; Choose the right 'udevd'. | ||
| 909 | (find file-exists? | ||
| 910 | (map (lambda (suffix) | ||
| 911 | (string-append #$udev suffix)) | ||
| 912 | '("/libexec/udev/udevd" ;udev | ||
| 913 | "/sbin/udevd")))) ;eudev | ||
| 914 | |||
| 915 | (define (wait-for-udevd) | ||
| 916 | ;; Wait until someone's listening on udevd's control | ||
| 917 | ;; socket. | ||
| 918 | (let ((sock (socket AF_UNIX SOCK_SEQPACKET 0))) | ||
| 919 | (let try () | ||
| 920 | (catch 'system-error | ||
| 921 | (lambda () | ||
| 922 | (connect sock PF_UNIX "/run/udev/control") | ||
| 923 | (close-port sock)) | ||
| 924 | (lambda args | ||
| 925 | (format #t "waiting for udevd...~%") | ||
| 926 | (usleep 500000) | ||
| 927 | (try)))))) | ||
| 928 | |||
| 929 | ;; Allow udev to find the modules. | ||
| 930 | (setenv "LINUX_MODULE_DIRECTORY" | ||
| 931 | "/run/booted-system/kernel/lib/modules") | ||
| 932 | |||
| 933 | ;; The first one is for udev, the second one for eudev. | ||
| 934 | (setenv "UDEV_CONFIG_FILE" #$udev.conf) | ||
| 935 | (setenv "EUDEV_RULES_DIRECTORY" | ||
| 936 | (string-append #$rules "/lib/udev/rules.d")) | ||
| 937 | |||
| 938 | (let ((pid (primitive-fork))) | ||
| 939 | (case pid | ||
| 940 | ((0) | ||
| 941 | (exec-command (list udevd))) | ||
| 942 | (else | ||
| 943 | ;; Wait until udevd is up and running. This | ||
| 944 | ;; appears to be needed so that the events | ||
| 945 | ;; triggered below are actually handled. | ||
| 946 | (wait-for-udevd) | ||
| 947 | |||
| 948 | ;; Trigger device node creation. | ||
| 949 | (system* (string-append #$udev "/bin/udevadm") | ||
| 950 | "trigger" "--action=add") | ||
| 951 | |||
| 952 | ;; Wait for things to settle down. | ||
| 953 | (system* (string-append #$udev "/bin/udevadm") | ||
| 954 | "settle") | ||
| 955 | pid))))) | ||
| 956 | (stop #~(make-kill-destructor)) | ||
| 957 | |||
| 958 | ;; When halting the system, 'udev' is actually killed by | ||
| 959 | ;; 'user-processes', i.e., before its own 'stop' method was called. | ||
| 960 | ;; Thus, make sure it is not respawned. | ||
| 961 | (respawn? #f))))))) | ||
| 962 | |||
| 963 | (define udev-service-type | ||
| 964 | (service-type (name 'udev) | ||
| 965 | (extensions | ||
| 966 | (list (service-extension dmd-root-service-type | ||
| 967 | udev-dmd-service))) | ||
| 968 | |||
| 969 | (compose concatenate) ;concatenate the list of rules | ||
| 970 | (extend (lambda (config rules) | ||
| 971 | (match config | ||
| 972 | (($ <udev-configuration> udev initial-rules) | ||
| 973 | (udev-configuration | ||
| 974 | (udev udev) | ||
| 975 | (rules (append initial-rules rules))))))))) | ||
| 976 | |||
| 730 | (define* (udev-service #:key (udev eudev) (rules '())) | 977 | (define* (udev-service #:key (udev eudev) (rules '())) |
| 731 | "Run @var{udev}, which populates the @file{/dev} directory dynamically. Get | 978 | "Run @var{udev}, which populates the @file{/dev} directory dynamically. Get |
| 732 | extra rules from the packages listed in @var{rules}." | 979 | extra rules from the packages listed in @var{rules}." |
| 733 | (let* ((rules (udev-rules-union (cons* udev | 980 | (service udev-service-type |
| 734 | (kvm-udev-rule) | 981 | (udev-configuration (udev udev) (rules rules)))) |
| 735 | rules))) | 982 | |
| 736 | (udev.conf (computed-file "udev.conf" | 983 | (define device-mapping-service-type |
| 737 | #~(call-with-output-file #$output | 984 | (dmd-service-type |
| 738 | (lambda (port) | 985 | (match-lambda |
| 739 | (format port | 986 | ((target open close) |
| 740 | "udev_rules=\"~a/lib/udev/rules.d\"\n" | 987 | (dmd-service |
| 741 | #$rules)))))) | 988 | (provision (list (symbol-append 'device-mapping- (string->symbol target)))) |
| 742 | (service | 989 | (requirement '(udev)) |
| 743 | (provision '(udev)) | 990 | (documentation "Map a device node using Linux's device mapper.") |
| 744 | 991 | (start #~(lambda () #$open)) | |
| 745 | ;; Udev needs /dev to be a 'devtmpfs' mount so that new device nodes can | 992 | (stop #~(lambda _ (not #$close))) |
| 746 | ;; be added: see | 993 | (respawn? #f)))))) |
| 747 | ;; <http://www.linuxfromscratch.org/lfs/view/development/chapter07/udev.html>. | ||
| 748 | (requirement '(root-file-system)) | ||
| 749 | |||
| 750 | (documentation "Populate the /dev directory, dynamically.") | ||
| 751 | (start #~(lambda () | ||
| 752 | (define find | ||
| 753 | (@ (srfi srfi-1) find)) | ||
| 754 | |||
| 755 | (define udevd | ||
| 756 | ;; Choose the right 'udevd'. | ||
| 757 | (find file-exists? | ||
| 758 | (map (lambda (suffix) | ||
| 759 | (string-append #$udev suffix)) | ||
| 760 | '("/libexec/udev/udevd" ;udev | ||
| 761 | "/sbin/udevd")))) ;eudev | ||
| 762 | |||
| 763 | (define (wait-for-udevd) | ||
| 764 | ;; Wait until someone's listening on udevd's control | ||
| 765 | ;; socket. | ||
| 766 | (let ((sock (socket AF_UNIX SOCK_SEQPACKET 0))) | ||
| 767 | (let try () | ||
| 768 | (catch 'system-error | ||
| 769 | (lambda () | ||
| 770 | (connect sock PF_UNIX "/run/udev/control") | ||
| 771 | (close-port sock)) | ||
| 772 | (lambda args | ||
| 773 | (format #t "waiting for udevd...~%") | ||
| 774 | (usleep 500000) | ||
| 775 | (try)))))) | ||
| 776 | |||
| 777 | ;; Allow udev to find the modules. | ||
| 778 | (setenv "LINUX_MODULE_DIRECTORY" | ||
| 779 | "/run/booted-system/kernel/lib/modules") | ||
| 780 | |||
| 781 | ;; The first one is for udev, the second one for eudev. | ||
| 782 | (setenv "UDEV_CONFIG_FILE" #$udev.conf) | ||
| 783 | (setenv "EUDEV_RULES_DIRECTORY" | ||
| 784 | (string-append #$rules "/lib/udev/rules.d")) | ||
| 785 | |||
| 786 | (let ((pid (primitive-fork))) | ||
| 787 | (case pid | ||
| 788 | ((0) | ||
| 789 | (exec-command (list udevd))) | ||
| 790 | (else | ||
| 791 | ;; Wait until udevd is up and running. This | ||
| 792 | ;; appears to be needed so that the events | ||
| 793 | ;; triggered below are actually handled. | ||
| 794 | (wait-for-udevd) | ||
| 795 | |||
| 796 | ;; Trigger device node creation. | ||
| 797 | (system* (string-append #$udev "/bin/udevadm") | ||
| 798 | "trigger" "--action=add") | ||
| 799 | |||
| 800 | ;; Wait for things to settle down. | ||
| 801 | (system* (string-append #$udev "/bin/udevadm") | ||
| 802 | "settle") | ||
| 803 | pid))))) | ||
| 804 | (stop #~(make-kill-destructor)) | ||
| 805 | |||
| 806 | ;; When halting the system, 'udev' is actually killed by | ||
| 807 | ;; 'user-processes', i.e., before its own 'stop' method was | ||
| 808 | ;; called. Thus, make sure it is not respawned. | ||
| 809 | (respawn? #f)))) | ||
| 810 | 994 | ||
| 811 | (define (device-mapping-service target open close) | 995 | (define (device-mapping-service target open close) |
| 812 | "Return a service that maps device @var{target}, a string such as | 996 | "Return a service that maps device @var{target}, a string such as |
| 813 | @code{\"home\"} (meaning @code{/dev/mapper/home}). Evaluate @var{open}, a | 997 | @code{\"home\"} (meaning @code{/dev/mapper/home}). Evaluate @var{open}, a |
| 814 | gexp, to open it, and evaluate @var{close} to close it." | 998 | gexp, to open it, and evaluate @var{close} to close it." |
| 815 | (service | 999 | (service device-mapping-service-type |
| 816 | (provision (list (symbol-append 'device-mapping- (string->symbol target)))) | 1000 | (list target open close))) |
| 817 | (requirement '(udev)) | 1001 | |
| 818 | (documentation "Map a device node using Linux's device mapper.") | 1002 | (define swap-service-type |
| 819 | (start #~(lambda () #$open)) | 1003 | (dmd-service-type |
| 820 | (stop #~(lambda _ (not #$close))) | 1004 | (lambda (device) |
| 821 | (respawn? #f))) | 1005 | (define requirement |
| 1006 | (if (string-prefix? "/dev/mapper/" device) | ||
| 1007 | (list (symbol-append 'device-mapping- | ||
| 1008 | (string->symbol (basename device)))) | ||
| 1009 | '())) | ||
| 1010 | |||
| 1011 | (dmd-service | ||
| 1012 | (provision (list (symbol-append 'swap- (string->symbol device)))) | ||
| 1013 | (requirement `(udev ,@requirement)) | ||
| 1014 | (documentation "Enable the given swap device.") | ||
| 1015 | (start #~(lambda () | ||
| 1016 | (restart-on-EINTR (swapon #$device)) | ||
| 1017 | #t)) | ||
| 1018 | (stop #~(lambda _ | ||
| 1019 | (restart-on-EINTR (swapoff #$device)) | ||
| 1020 | #f)) | ||
| 1021 | (respawn? #f))))) | ||
| 822 | 1022 | ||
| 823 | (define (swap-service device) | 1023 | (define (swap-service device) |
| 824 | "Return a service that uses @var{device} as a swap device." | 1024 | "Return a service that uses @var{device} as a swap device." |
| 825 | (define requirement | 1025 | (service swap-service-type device)) |
| 826 | (if (string-prefix? "/dev/mapper/" device) | ||
| 827 | (list (symbol-append 'device-mapping- | ||
| 828 | (string->symbol (basename device)))) | ||
| 829 | '())) | ||
| 830 | |||
| 831 | (service | ||
| 832 | (provision (list (symbol-append 'swap- (string->symbol device)))) | ||
| 833 | (requirement `(udev ,@requirement)) | ||
| 834 | (documentation "Enable the given swap device.") | ||
| 835 | (start #~(lambda () | ||
| 836 | (restart-on-EINTR (swapon #$device)) | ||
| 837 | #t)) | ||
| 838 | (stop #~(lambda _ | ||
| 839 | (restart-on-EINTR (swapoff #$device)) | ||
| 840 | #f)) | ||
| 841 | (respawn? #f))) | ||
| 842 | 1026 | ||
| 843 | (define %base-services | 1027 | (define %base-services |
| 844 | ;; Convenience variable holding the basic services. | 1028 | ;; Convenience variable holding the basic services. |
| @@ -873,9 +1057,6 @@ This is the GNU operating system, welcome!\n\n"))) | |||
| 873 | ;; The LVM2 rules are needed as soon as LVM2 or the device-mapper is | 1057 | ;; The LVM2 rules are needed as soon as LVM2 or the device-mapper is |
| 874 | ;; used, so enable them by default. The FUSE and ALSA rules are | 1058 | ;; used, so enable them by default. The FUSE and ALSA rules are |
| 875 | ;; less critical, but handy. | 1059 | ;; less critical, but handy. |
| 876 | ;; | ||
| 877 | ;; XXX Keep this in sync with the 'udev-service' call in | ||
| 878 | ;; %desktop-services. | ||
| 879 | (udev-service #:rules (list lvm2 fuse alsa-utils crda))))) | 1060 | (udev-service #:rules (list lvm2 fuse alsa-utils crda))))) |
| 880 | 1061 | ||
| 881 | ;;; base.scm ends here | 1062 | ;;; base.scm ends here |
diff --git a/gnu/services/databases.scm b/gnu/services/databases.scm index 20f8a6977eb..8fdd222a3bf 100644 --- a/gnu/services/databases.scm +++ b/gnu/services/databases.scm | |||
| @@ -19,12 +19,13 @@ | |||
| 19 | 19 | ||
| 20 | (define-module (gnu services databases) | 20 | (define-module (gnu services databases) |
| 21 | #:use-module (gnu services) | 21 | #:use-module (gnu services) |
| 22 | #:use-module (gnu services dmd) | ||
| 22 | #:use-module (gnu system shadow) | 23 | #:use-module (gnu system shadow) |
| 23 | #:use-module (gnu packages admin) | 24 | #:use-module (gnu packages admin) |
| 24 | #:use-module (gnu packages databases) | 25 | #:use-module (gnu packages databases) |
| 25 | #:use-module (guix records) | 26 | #:use-module (guix records) |
| 26 | #:use-module (guix store) | ||
| 27 | #:use-module (guix gexp) | 27 | #:use-module (guix gexp) |
| 28 | #:use-module (ice-9 match) | ||
| 28 | #:export (postgresql-service)) | 29 | #:export (postgresql-service)) |
| 29 | 30 | ||
| 30 | ;;; Commentary: | 31 | ;;; Commentary: |
| @@ -33,6 +34,14 @@ | |||
| 33 | ;;; | 34 | ;;; |
| 34 | ;;; Code: | 35 | ;;; Code: |
| 35 | 36 | ||
| 37 | (define-record-type* <postgresql-configuration> | ||
| 38 | postgresql-configuration make-postgresql-configuration | ||
| 39 | postgresql-configuration? | ||
| 40 | (postgresql postgresql-configuration-postgresql ;<package> | ||
| 41 | (default postgresql)) | ||
| 42 | (config-file postgresql-configuration-file) | ||
| 43 | (data-directory postgresql-configuration-data-directory)) | ||
| 44 | |||
| 36 | (define %default-postgres-hba | 45 | (define %default-postgres-hba |
| 37 | (plain-file "pg_hba.conf" | 46 | (plain-file "pg_hba.conf" |
| 38 | " | 47 | " |
| @@ -49,6 +58,77 @@ host all all ::1/128 trust")) | |||
| 49 | "hba_file = '" %default-postgres-hba "'\n" | 58 | "hba_file = '" %default-postgres-hba "'\n" |
| 50 | "ident_file = '" %default-postgres-ident "\n")) | 59 | "ident_file = '" %default-postgres-ident "\n")) |
| 51 | 60 | ||
| 61 | (define %postgresql-accounts | ||
| 62 | (list (user-group (name "postgres") (system? #t)) | ||
| 63 | (user-account | ||
| 64 | (name "postgres") | ||
| 65 | (group "postgres") | ||
| 66 | (system? #t) | ||
| 67 | (comment "PostgreSQL server user") | ||
| 68 | (home-directory "/var/empty") | ||
| 69 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 70 | |||
| 71 | (define postgresql-activation | ||
| 72 | (match-lambda | ||
| 73 | (($ <postgresql-configuration> postgresql config-file data-directory) | ||
| 74 | #~(begin | ||
| 75 | (use-modules (guix build utils) | ||
| 76 | (ice-9 match)) | ||
| 77 | |||
| 78 | (let ((user (getpwnam "postgres")) | ||
| 79 | (initdb (string-append #$postgresql "/bin/initdb"))) | ||
| 80 | ;; Create db state directory. | ||
| 81 | (mkdir-p #$data-directory) | ||
| 82 | (chown #$data-directory (passwd:uid user) (passwd:gid user)) | ||
| 83 | |||
| 84 | ;; Drop privileges and init state directory in a new | ||
| 85 | ;; process. Wait for it to finish before proceeding. | ||
| 86 | (match (primitive-fork) | ||
| 87 | (0 | ||
| 88 | ;; Exit with a non-zero status code if an exception is thrown. | ||
| 89 | (dynamic-wind | ||
| 90 | (const #t) | ||
| 91 | (lambda () | ||
| 92 | (setgid (passwd:gid user)) | ||
| 93 | (setuid (passwd:uid user)) | ||
| 94 | (primitive-exit (system* initdb "-D" #$data-directory))) | ||
| 95 | (lambda () | ||
| 96 | (primitive-exit 1)))) | ||
| 97 | (pid (waitpid pid)))))))) | ||
| 98 | |||
| 99 | (define postgresql-dmd-service | ||
| 100 | (match-lambda | ||
| 101 | (($ <postgresql-configuration> postgresql config-file data-directory) | ||
| 102 | (let ((start-script | ||
| 103 | ;; Wrapper script that switches to the 'postgres' user before | ||
| 104 | ;; launching daemon. | ||
| 105 | (program-file "start-postgres" | ||
| 106 | #~(let ((user (getpwnam "postgres")) | ||
| 107 | (postgres (string-append #$postgresql | ||
| 108 | "/bin/postgres"))) | ||
| 109 | (setgid (passwd:gid user)) | ||
| 110 | (setuid (passwd:uid user)) | ||
| 111 | (system* postgres | ||
| 112 | (string-append "--config-file=" | ||
| 113 | #$config-file) | ||
| 114 | "-D" #$data-directory))))) | ||
| 115 | (list (dmd-service | ||
| 116 | (provision '(postgres)) | ||
| 117 | (documentation "Run the PostgreSQL daemon.") | ||
| 118 | (requirement '(user-processes loopback)) | ||
| 119 | (start #~(make-forkexec-constructor #$start-script)) | ||
| 120 | (stop #~(make-kill-destructor)))))))) | ||
| 121 | |||
| 122 | (define postgresql-service-type | ||
| 123 | (service-type (name 'postgresql) | ||
| 124 | (extensions | ||
| 125 | (list (service-extension dmd-root-service-type | ||
| 126 | postgresql-dmd-service) | ||
| 127 | (service-extension activation-service-type | ||
| 128 | postgresql-activation) | ||
| 129 | (service-extension account-service-type | ||
| 130 | (const %postgresql-accounts)))))) | ||
| 131 | |||
| 52 | (define* (postgresql-service #:key (postgresql postgresql) | 132 | (define* (postgresql-service #:key (postgresql postgresql) |
| 53 | (config-file %default-postgres-config) | 133 | (config-file %default-postgres-config) |
| 54 | (data-directory "/var/lib/postgresql/data")) | 134 | (data-directory "/var/lib/postgresql/data")) |
| @@ -56,60 +136,8 @@ host all all ::1/128 trust")) | |||
| 56 | 136 | ||
| 57 | The PostgreSQL daemon loads its runtime configuration from @var{config-file} | 137 | The PostgreSQL daemon loads its runtime configuration from @var{config-file} |
| 58 | and stores the database cluster in @var{data-directory}." | 138 | and stores the database cluster in @var{data-directory}." |
| 59 | ;; Wrapper script that switches to the 'postgres' user before launching | 139 | (service postgresql-service-type |
| 60 | ;; daemon. | 140 | (postgresql-configuration |
| 61 | (define start-script | 141 | (postgresql postgresql) |
| 62 | (program-file "start-postgres" | 142 | (config-file config-file) |
| 63 | #~(let ((user (getpwnam "postgres")) | 143 | (data-directory data-directory)))) |
| 64 | (postgres (string-append #$postgresql | ||
| 65 | "/bin/postgres"))) | ||
| 66 | (setgid (passwd:gid user)) | ||
| 67 | (setuid (passwd:uid user)) | ||
| 68 | (system* postgres | ||
| 69 | (string-append "--config-file=" #$config-file) | ||
| 70 | "-D" #$data-directory)))) | ||
| 71 | |||
| 72 | (define activate | ||
| 73 | #~(begin | ||
| 74 | (use-modules (guix build utils) | ||
| 75 | (ice-9 match)) | ||
| 76 | |||
| 77 | (let ((user (getpwnam "postgres")) | ||
| 78 | (initdb (string-append #$postgresql "/bin/initdb"))) | ||
| 79 | ;; Create db state directory. | ||
| 80 | (mkdir-p #$data-directory) | ||
| 81 | (chown #$data-directory (passwd:uid user) (passwd:gid user)) | ||
| 82 | |||
| 83 | ;; Drop privileges and init state directory in a new | ||
| 84 | ;; process. Wait for it to finish before proceeding. | ||
| 85 | (match (primitive-fork) | ||
| 86 | (0 | ||
| 87 | ;; Exit with a non-zero status code if an exception is thrown. | ||
| 88 | (dynamic-wind | ||
| 89 | (const #t) | ||
| 90 | (lambda () | ||
| 91 | (setgid (passwd:gid user)) | ||
| 92 | (setuid (passwd:uid user)) | ||
| 93 | (primitive-exit (system* initdb "-D" #$data-directory))) | ||
| 94 | (lambda () | ||
| 95 | (primitive-exit 1)))) | ||
| 96 | (pid (waitpid pid)))))) | ||
| 97 | |||
| 98 | (service | ||
| 99 | (provision '(postgres)) | ||
| 100 | (documentation "Run the PostgreSQL daemon.") | ||
| 101 | (requirement '(user-processes loopback)) | ||
| 102 | (start #~(make-forkexec-constructor #$start-script)) | ||
| 103 | (stop #~(make-kill-destructor)) | ||
| 104 | (activate activate) | ||
| 105 | (user-groups (list (user-group | ||
| 106 | (name "postgres") | ||
| 107 | (system? #t)))) | ||
| 108 | (user-accounts (list (user-account | ||
| 109 | (name "postgres") | ||
| 110 | (group "postgres") | ||
| 111 | (system? #t) | ||
| 112 | (comment "PostgreSQL server user") | ||
| 113 | (home-directory "/var/empty") | ||
| 114 | (shell | ||
| 115 | #~(string-append #$shadow "/sbin/nologin"))))))) | ||
diff --git a/gnu/services/dbus.scm b/gnu/services/dbus.scm new file mode 100644 index 00000000000..e4ecd961c57 --- /dev/null +++ b/gnu/services/dbus.scm | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (gnu services dbus) | ||
| 20 | #:use-module (gnu services) | ||
| 21 | #:use-module (gnu services dmd) | ||
| 22 | #:use-module (gnu system shadow) | ||
| 23 | #:use-module (gnu packages glib) | ||
| 24 | #:use-module (gnu packages admin) | ||
| 25 | #:use-module (guix gexp) | ||
| 26 | #:use-module (guix records) | ||
| 27 | #:use-module (srfi srfi-1) | ||
| 28 | #:use-module (ice-9 match) | ||
| 29 | #:export (dbus-root-service-type | ||
| 30 | dbus-service)) | ||
| 31 | |||
| 32 | ;;; | ||
| 33 | ;;; D-Bus. | ||
| 34 | ;;; | ||
| 35 | |||
| 36 | (define-record-type* <dbus-configuration> | ||
| 37 | dbus-configuration make-dbus-configuration | ||
| 38 | dbus-configuration? | ||
| 39 | (dbus dbus-configuration-dbus ;<package> | ||
| 40 | (default dbus)) | ||
| 41 | (services dbus-configuration-services ;list of <package> | ||
| 42 | (default '()))) | ||
| 43 | |||
| 44 | (define (dbus-configuration-directory dbus services) | ||
| 45 | "Return a configuration directory for @var{dbus} that includes the | ||
| 46 | @code{etc/dbus-1/system.d} directories of each package listed in | ||
| 47 | @var{services}." | ||
| 48 | (define build | ||
| 49 | #~(begin | ||
| 50 | (use-modules (sxml simple) | ||
| 51 | (srfi srfi-1)) | ||
| 52 | |||
| 53 | (define (services->sxml services) | ||
| 54 | ;; Return the SXML 'includedir' clauses for DIRS. | ||
| 55 | `(busconfig | ||
| 56 | ,@(append-map (lambda (dir) | ||
| 57 | `((includedir | ||
| 58 | ,(string-append dir "/etc/dbus-1/system.d")) | ||
| 59 | (servicedir ;for '.service' files | ||
| 60 | ,(string-append dir "/share/dbus-1/services")) | ||
| 61 | (servicedir ;likewise, for auto-activation | ||
| 62 | ,(string-append | ||
| 63 | dir | ||
| 64 | "/share/dbus-1/system-services")))) | ||
| 65 | services))) | ||
| 66 | |||
| 67 | (mkdir #$output) | ||
| 68 | (copy-file (string-append #$dbus "/etc/dbus-1/system.conf") | ||
| 69 | (string-append #$output "/system.conf")) | ||
| 70 | |||
| 71 | ;; The default 'system.conf' has an <includedir> clause for | ||
| 72 | ;; 'system.d', so create it. | ||
| 73 | (mkdir (string-append #$output "/system.d")) | ||
| 74 | |||
| 75 | ;; 'system-local.conf' is automatically included by the default | ||
| 76 | ;; 'system.conf', so this is where we stuff our own things. | ||
| 77 | (call-with-output-file (string-append #$output "/system-local.conf") | ||
| 78 | (lambda (port) | ||
| 79 | (sxml->xml (services->sxml (list #$@services)) | ||
| 80 | port))))) | ||
| 81 | |||
| 82 | (computed-file "dbus-configuration" build)) | ||
| 83 | |||
| 84 | (define %dbus-accounts | ||
| 85 | ;; Accounts used by the system bus. | ||
| 86 | (list (user-group (name "messagebus") (system? #t)) | ||
| 87 | (user-account | ||
| 88 | (name "messagebus") | ||
| 89 | (group "messagebus") | ||
| 90 | (system? #t) | ||
| 91 | (comment "D-Bus system bus user") | ||
| 92 | (home-directory "/var/run/dbus") | ||
| 93 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 94 | |||
| 95 | (define (dbus-activation config) | ||
| 96 | "Return an activation gexp for D-Bus using @var{config}." | ||
| 97 | #~(begin | ||
| 98 | (use-modules (guix build utils)) | ||
| 99 | |||
| 100 | (mkdir-p "/var/run/dbus") | ||
| 101 | |||
| 102 | (let ((user (getpwnam "messagebus"))) | ||
| 103 | (chown "/var/run/dbus" | ||
| 104 | (passwd:uid user) (passwd:gid user))) | ||
| 105 | |||
| 106 | (unless (file-exists? "/etc/machine-id") | ||
| 107 | (format #t "creating /etc/machine-id...~%") | ||
| 108 | (let ((prog (string-append #$(dbus-configuration-dbus config) | ||
| 109 | "/bin/dbus-uuidgen"))) | ||
| 110 | ;; XXX: We can't use 'system' because the initrd's | ||
| 111 | ;; guile system(3) only works when 'sh' is in $PATH. | ||
| 112 | (let ((pid (primitive-fork))) | ||
| 113 | (if (zero? pid) | ||
| 114 | (call-with-output-file "/etc/machine-id" | ||
| 115 | (lambda (port) | ||
| 116 | (close-fdes 1) | ||
| 117 | (dup2 (port->fdes port) 1) | ||
| 118 | (execl prog))) | ||
| 119 | (waitpid pid))))))) | ||
| 120 | |||
| 121 | (define dbus-dmd-service | ||
| 122 | (match-lambda | ||
| 123 | (($ <dbus-configuration> dbus services) | ||
| 124 | (let ((conf (dbus-configuration-directory dbus services))) | ||
| 125 | (list (dmd-service | ||
| 126 | (documentation "Run the D-Bus system daemon.") | ||
| 127 | (provision '(dbus-system)) | ||
| 128 | (requirement '(user-processes)) | ||
| 129 | (start #~(make-forkexec-constructor | ||
| 130 | (list (string-append #$dbus "/bin/dbus-daemon") | ||
| 131 | "--nofork" | ||
| 132 | (string-append "--config-file=" #$conf | ||
| 133 | "/system.conf")))) | ||
| 134 | (stop #~(make-kill-destructor)))))))) | ||
| 135 | |||
| 136 | (define dbus-root-service-type | ||
| 137 | (service-type (name 'dbus) | ||
| 138 | (extensions | ||
| 139 | (list (service-extension dmd-root-service-type | ||
| 140 | dbus-dmd-service) | ||
| 141 | (service-extension activation-service-type | ||
| 142 | dbus-activation) | ||
| 143 | (service-extension account-service-type | ||
| 144 | (const %dbus-accounts)))) | ||
| 145 | |||
| 146 | ;; Extensions consist of lists of packages (representing D-Bus | ||
| 147 | ;; services) that we just concatenate. | ||
| 148 | ;; | ||
| 149 | ;; FIXME: We need 'dbus-daemon-launch-helper' to be | ||
| 150 | ;; setuid-root for auto-activation to work. | ||
| 151 | (compose concatenate) | ||
| 152 | |||
| 153 | ;; The service's parameters field is extended by augmenting | ||
| 154 | ;; its <dbus-configuration> 'services' field. | ||
| 155 | (extend (lambda (config services) | ||
| 156 | (dbus-configuration | ||
| 157 | (inherit config) | ||
| 158 | (services | ||
| 159 | (append (dbus-configuration-services config) | ||
| 160 | services))))))) | ||
| 161 | |||
| 162 | (define* (dbus-service #:key (dbus dbus) (services '())) | ||
| 163 | "Return a service that runs the \"system bus\", using @var{dbus}, with | ||
| 164 | support for @var{services}. | ||
| 165 | |||
| 166 | @uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication | ||
| 167 | facility. Its system bus is used to allow system services to communicate and | ||
| 168 | be notified of system-wide events. | ||
| 169 | |||
| 170 | @var{services} must be a list of packages that provide an | ||
| 171 | @file{etc/dbus-1/system.d} directory containing additional D-Bus configuration | ||
| 172 | and policy files. For example, to allow avahi-daemon to use the system bus, | ||
| 173 | @var{services} must be equal to @code{(list avahi)}." | ||
| 174 | (service dbus-root-service-type | ||
| 175 | (dbus-configuration (dbus dbus) | ||
| 176 | (services services)))) | ||
| 177 | |||
| 178 | ;;; dbus.scm ends here | ||
diff --git a/gnu/services/desktop.scm b/gnu/services/desktop.scm index 346f9169502..cf1ce8269d5 100644 --- a/gnu/services/desktop.scm +++ b/gnu/services/desktop.scm | |||
| @@ -20,7 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | (define-module (gnu services desktop) | 21 | (define-module (gnu services desktop) |
| 22 | #:use-module (gnu services) | 22 | #:use-module (gnu services) |
| 23 | #:use-module (gnu services dmd) | ||
| 23 | #:use-module (gnu services base) | 24 | #:use-module (gnu services base) |
| 25 | #:use-module (gnu services dbus) | ||
| 24 | #:use-module (gnu services avahi) | 26 | #:use-module (gnu services avahi) |
| 25 | #:use-module (gnu services xorg) | 27 | #:use-module (gnu services xorg) |
| 26 | #:use-module (gnu services networking) | 28 | #:use-module (gnu services networking) |
| @@ -31,16 +33,14 @@ | |||
| 31 | #:use-module (gnu packages freedesktop) | 33 | #:use-module (gnu packages freedesktop) |
| 32 | #:use-module (gnu packages gnome) | 34 | #:use-module (gnu packages gnome) |
| 33 | #:use-module (gnu packages avahi) | 35 | #:use-module (gnu packages avahi) |
| 34 | #:use-module (gnu packages wicd) | ||
| 35 | #:use-module (gnu packages polkit) | 36 | #:use-module (gnu packages polkit) |
| 36 | #:use-module ((gnu packages linux) | ||
| 37 | #:select (lvm2 fuse alsa-utils crda)) | ||
| 38 | #:use-module (guix records) | 37 | #:use-module (guix records) |
| 38 | #:use-module (guix packages) | ||
| 39 | #:use-module (guix store) | 39 | #:use-module (guix store) |
| 40 | #:use-module (guix gexp) | 40 | #:use-module (guix gexp) |
| 41 | #:use-module (srfi srfi-1) | ||
| 41 | #:use-module (ice-9 match) | 42 | #:use-module (ice-9 match) |
| 42 | #:export (dbus-service | 43 | #:export (upower-service |
| 43 | upower-service | ||
| 44 | colord-service | 44 | colord-service |
| 45 | geoclue-application | 45 | geoclue-application |
| 46 | %standard-geoclue-applications | 46 | %standard-geoclue-applications |
| @@ -64,133 +64,149 @@ | |||
| 64 | (define (bool value) | 64 | (define (bool value) |
| 65 | (if value "true\n" "false\n")) | 65 | (if value "true\n" "false\n")) |
| 66 | 66 | ||
| 67 | |||
| 68 | ;;; | ||
| 69 | ;;; D-Bus. | ||
| 70 | ;;; | ||
| 71 | 67 | ||
| 72 | (define (dbus-configuration-directory dbus services) | 68 | (define (wrapped-dbus-service service program variable value) |
| 73 | "Return a configuration directory for @var{dbus} that includes the | 69 | "Return a wrapper for @var{service}, a package containing a D-Bus service, |
| 74 | @code{etc/dbus-1/system.d} directories of each package listed in | 70 | where @var{program} is wrapped such that environment variable @var{variable} |
| 75 | @var{services}." | 71 | is set to @var{value} when the bus daemon launches it." |
| 76 | (define build | 72 | (define wrapper |
| 77 | #~(begin | 73 | (program-file (string-append (package-name service) "-program-wrapper") |
| 78 | (use-modules (sxml simple) | 74 | #~(begin |
| 79 | (srfi srfi-1)) | 75 | (setenv #$variable #$value) |
| 80 | 76 | (apply execl (string-append #$service "/" #$program) | |
| 81 | (define (services->sxml services) | 77 | (string-append #$service "/" #$program) |
| 82 | ;; Return the SXML 'includedir' clauses for DIRS. | 78 | (cdr (command-line)))))) |
| 83 | `(busconfig | 79 | |
| 84 | ,@(append-map (lambda (dir) | 80 | (computed-file (string-append (package-name service) "-wrapper") |
| 85 | `((includedir | 81 | #~(begin |
| 86 | ,(string-append dir "/etc/dbus-1/system.d")) | 82 | (use-modules (guix build utils)) |
| 87 | (servicedir ;for '.service' files | 83 | |
| 88 | ,(string-append dir "/share/dbus-1/services")))) | 84 | (define service-directory |
| 89 | services))) | 85 | "/share/dbus-1/system-services") |
| 90 | 86 | ||
| 91 | (mkdir #$output) | 87 | (mkdir-p (dirname (string-append #$output |
| 92 | (copy-file (string-append #$dbus "/etc/dbus-1/system.conf") | 88 | service-directory))) |
| 93 | (string-append #$output "/system.conf")) | 89 | (copy-recursively (string-append #$service |
| 94 | 90 | service-directory) | |
| 95 | ;; The default 'system.conf' has an <includedir> clause for | 91 | (string-append #$output |
| 96 | ;; 'system.d', so create it. | 92 | service-directory)) |
| 97 | (mkdir (string-append #$output "/system.d")) | 93 | (symlink (string-append #$service "/etc") ;for etc/dbus-1 |
| 98 | 94 | (string-append #$output "/etc")) | |
| 99 | ;; 'system-local.conf' is automatically included by the default | 95 | |
| 100 | ;; 'system.conf', so this is where we stuff our own things. | 96 | (for-each (lambda (file) |
| 101 | (call-with-output-file (string-append #$output "/system-local.conf") | 97 | (substitute* file |
| 102 | (lambda (port) | 98 | (("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$" |
| 103 | (sxml->xml (services->sxml (list #$@services)) | 99 | _ original-program arguments) |
| 104 | port))))) | 100 | (string-append "Exec=" #$wrapper arguments |
| 105 | 101 | "\n")))) | |
| 106 | (computed-file "dbus-configuration" build)) | 102 | (find-files #$output "\\.service$"))) |
| 107 | 103 | #:modules '((guix build utils)))) | |
| 108 | (define* (dbus-service services #:key (dbus dbus)) | ||
| 109 | "Return a service that runs the \"system bus\", using @var{dbus}, with | ||
| 110 | support for @var{services}. | ||
| 111 | |||
| 112 | @uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication | ||
| 113 | facility. Its system bus is used to allow system services to communicate and | ||
| 114 | be notified of system-wide events. | ||
| 115 | |||
| 116 | @var{services} must be a list of packages that provide an | ||
| 117 | @file{etc/dbus-1/system.d} directory containing additional D-Bus configuration | ||
| 118 | and policy files. For example, to allow avahi-daemon to use the system bus, | ||
| 119 | @var{services} must be equal to @code{(list avahi)}." | ||
| 120 | (let ((conf (dbus-configuration-directory dbus services))) | ||
| 121 | (service | ||
| 122 | (documentation "Run the D-Bus system daemon.") | ||
| 123 | (provision '(dbus-system)) | ||
| 124 | (requirement '(user-processes)) | ||
| 125 | (start #~(make-forkexec-constructor | ||
| 126 | (list (string-append #$dbus "/bin/dbus-daemon") | ||
| 127 | "--nofork" | ||
| 128 | (string-append "--config-file=" #$conf "/system.conf")))) | ||
| 129 | (stop #~(make-kill-destructor)) | ||
| 130 | (user-groups (list (user-group | ||
| 131 | (name "messagebus") | ||
| 132 | (system? #t)))) | ||
| 133 | (user-accounts (list (user-account | ||
| 134 | (name "messagebus") | ||
| 135 | (group "messagebus") | ||
| 136 | (system? #t) | ||
| 137 | (comment "D-Bus system bus user") | ||
| 138 | (home-directory "/var/run/dbus") | ||
| 139 | (shell | ||
| 140 | #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 141 | (activate #~(begin | ||
| 142 | (use-modules (guix build utils)) | ||
| 143 | |||
| 144 | (mkdir-p "/var/run/dbus") | ||
| 145 | |||
| 146 | (let ((user (getpwnam "messagebus"))) | ||
| 147 | (chown "/var/run/dbus" | ||
| 148 | (passwd:uid user) (passwd:gid user))) | ||
| 149 | |||
| 150 | (unless (file-exists? "/etc/machine-id") | ||
| 151 | (format #t "creating /etc/machine-id...~%") | ||
| 152 | (let ((prog (string-append #$dbus "/bin/dbus-uuidgen"))) | ||
| 153 | ;; XXX: We can't use 'system' because the initrd's | ||
| 154 | ;; guile system(3) only works when 'sh' is in $PATH. | ||
| 155 | (let ((pid (primitive-fork))) | ||
| 156 | (if (zero? pid) | ||
| 157 | (call-with-output-file "/etc/machine-id" | ||
| 158 | (lambda (port) | ||
| 159 | (close-fdes 1) | ||
| 160 | (dup2 (port->fdes port) 1) | ||
| 161 | (execl prog))) | ||
| 162 | (waitpid pid)))))))))) | ||
| 163 | 104 | ||
| 164 | 105 | ||
| 165 | ;;; | 106 | ;;; |
| 166 | ;;; Upower D-Bus service. | 107 | ;;; Upower D-Bus service. |
| 167 | ;;; | 108 | ;;; |
| 168 | 109 | ||
| 169 | (define* (upower-configuration-file #:key watts-up-pro? poll-batteries? | 110 | ;; TODO: Export. |
| 170 | ignore-lid? use-percentage-for-policy? | 111 | (define-record-type* <upower-configuration> |
| 171 | percentage-low percentage-critical | 112 | upower-configuration make-upower-configuration |
| 172 | percentage-action time-low | 113 | upower-configuration? |
| 173 | time-critical time-action | 114 | (upower upower-configuration-upower |
| 174 | critical-power-action) | 115 | (default upower)) |
| 175 | "Return an upower-daemon configuration file." | 116 | (watts-up-pro? upower-configuration-watts-up-pro?) |
| 176 | (plain-file "UPower.conf" | 117 | (poll-batteries? upower-configuration-poll-batteries?) |
| 177 | (string-append | 118 | (ignore-lid? upower-configuration-ignore-lid?) |
| 178 | "[UPower]\n" | 119 | (use-percentage-for-policy? upower-configuration-use-percentage-for-policy?) |
| 179 | "EnableWattsUpPro=" (bool watts-up-pro?) | 120 | (percentage-low upower-configuration-percentage-low) |
| 180 | "NoPollBatteries=" (bool (not poll-batteries?)) | 121 | (percentage-critical upower-configuration-percentage-critical) |
| 181 | "IgnoreLid=" (bool ignore-lid?) | 122 | (percentage-action upower-configuration-percentage-action) |
| 182 | "UsePercentageForPolicy=" (bool use-percentage-for-policy?) | 123 | (time-low upower-configuration-time-low) |
| 183 | "PercentageLow=" (number->string percentage-low) "\n" | 124 | (time-critical upower-configuration-time-critical) |
| 184 | "PercentageCritical=" (number->string percentage-critical) "\n" | 125 | (time-action upower-configuration-time-action) |
| 185 | "PercentageAction=" (number->string percentage-action) "\n" | 126 | (critical-power-action upower-configuration-critical-power-action)) |
| 186 | "TimeLow=" (number->string time-low) "\n" | 127 | |
| 187 | "TimeCritical=" (number->string time-critical) "\n" | 128 | (define* upower-configuration-file |
| 188 | "TimeAction=" (number->string time-action) "\n" | 129 | ;; Return an upower-daemon configuration file. |
| 189 | "CriticalPowerAction=" (match critical-power-action | 130 | (match-lambda |
| 190 | ('hybrid-sleep "HybridSleep") | 131 | (($ <upower-configuration> upower |
| 191 | ('hibernate "Hibernate") | 132 | watts-up-pro? poll-batteries? ignore-lid? use-percentage-for-policy? |
| 192 | ('power-off "PowerOff")) | 133 | percentage-low percentage-critical percentage-action time-low |
| 193 | "\n"))) | 134 | time-critical time-action critical-power-action) |
| 135 | (plain-file "UPower.conf" | ||
| 136 | (string-append | ||
| 137 | "[UPower]\n" | ||
| 138 | "EnableWattsUpPro=" (bool watts-up-pro?) | ||
| 139 | "NoPollBatteries=" (bool (not poll-batteries?)) | ||
| 140 | "IgnoreLid=" (bool ignore-lid?) | ||
| 141 | "UsePercentageForPolicy=" (bool use-percentage-for-policy?) | ||
| 142 | "PercentageLow=" (number->string percentage-low) "\n" | ||
| 143 | "PercentageCritical=" (number->string percentage-critical) "\n" | ||
| 144 | "PercentageAction=" (number->string percentage-action) "\n" | ||
| 145 | "TimeLow=" (number->string time-low) "\n" | ||
| 146 | "TimeCritical=" (number->string time-critical) "\n" | ||
| 147 | "TimeAction=" (number->string time-action) "\n" | ||
| 148 | "CriticalPowerAction=" (match critical-power-action | ||
| 149 | ('hybrid-sleep "HybridSleep") | ||
| 150 | ('hibernate "Hibernate") | ||
| 151 | ('power-off "PowerOff")) | ||
| 152 | "\n"))))) | ||
| 153 | |||
| 154 | (define %upower-accounts ;XXX: useful? | ||
| 155 | (list (user-group (name "upower") (system? #t)) | ||
| 156 | (user-account | ||
| 157 | (name "upower") | ||
| 158 | (group "upower") | ||
| 159 | (system? #t) | ||
| 160 | (comment "UPower daemon user") | ||
| 161 | (home-directory "/var/empty") | ||
| 162 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 163 | |||
| 164 | (define %upower-activation | ||
| 165 | #~(begin | ||
| 166 | (use-modules (guix build utils)) | ||
| 167 | (mkdir-p "/var/lib/upower") | ||
| 168 | (let ((user (getpwnam "upower"))) | ||
| 169 | (chown "/var/lib/upower" | ||
| 170 | (passwd:uid user) (passwd:gid user))))) | ||
| 171 | |||
| 172 | |||
| 173 | (define (upower-dbus-service config) | ||
| 174 | (list (wrapped-dbus-service (upower-configuration-upower config) | ||
| 175 | "libexec/upowerd" | ||
| 176 | "UPOWER_CONF_FILE_NAME" | ||
| 177 | (upower-configuration-file config)))) | ||
| 178 | |||
| 179 | (define (upower-dmd-service config) | ||
| 180 | "Return a dmd service for UPower with CONFIG." | ||
| 181 | (let ((upower (upower-configuration-upower config)) | ||
| 182 | (config (upower-configuration-file config))) | ||
| 183 | (list (dmd-service | ||
| 184 | (documentation "Run the UPower power and battery monitor.") | ||
| 185 | (provision '(upower-daemon)) | ||
| 186 | (requirement '(dbus-system udev)) | ||
| 187 | |||
| 188 | (start #~(make-forkexec-constructor | ||
| 189 | (list (string-append #$upower "/libexec/upowerd")) | ||
| 190 | #:environment-variables | ||
| 191 | (list (string-append "UPOWER_CONF_FILE_NAME=" | ||
| 192 | #$config)))) | ||
| 193 | (stop #~(make-kill-destructor)))))) | ||
| 194 | |||
| 195 | (define upower-service-type | ||
| 196 | (service-type (name 'upower) | ||
| 197 | (extensions | ||
| 198 | (list (service-extension dbus-root-service-type | ||
| 199 | upower-dbus-service) | ||
| 200 | (service-extension dmd-root-service-type | ||
| 201 | upower-dmd-service) | ||
| 202 | (service-extension account-service-type | ||
| 203 | (const %upower-accounts)) | ||
| 204 | (service-extension activation-service-type | ||
| 205 | (const %upower-activation)) | ||
| 206 | (service-extension udev-service-type | ||
| 207 | (compose | ||
| 208 | list | ||
| 209 | upower-configuration-upower)))))) | ||
| 194 | 210 | ||
| 195 | (define* (upower-service #:key (upower upower) | 211 | (define* (upower-service #:key (upower upower) |
| 196 | (watts-up-pro? #f) | 212 | (watts-up-pro? #f) |
| @@ -208,90 +224,97 @@ and policy files. For example, to allow avahi-daemon to use the system bus, | |||
| 208 | @command{upowerd}}, a system-wide monitor for power consumption and battery | 224 | @command{upowerd}}, a system-wide monitor for power consumption and battery |
| 209 | levels, with the given configuration settings. It implements the | 225 | levels, with the given configuration settings. It implements the |
| 210 | @code{org.freedesktop.UPower} D-Bus interface, and is notably used by GNOME." | 226 | @code{org.freedesktop.UPower} D-Bus interface, and is notably used by GNOME." |
| 211 | (let ((config (upower-configuration-file | 227 | (let ((config (upower-configuration |
| 212 | #:watts-up-pro? watts-up-pro? | 228 | (watts-up-pro? watts-up-pro?) |
| 213 | #:poll-batteries? poll-batteries? | 229 | (poll-batteries? poll-batteries?) |
| 214 | #:ignore-lid? ignore-lid? | 230 | (ignore-lid? ignore-lid?) |
| 215 | #:use-percentage-for-policy? use-percentage-for-policy? | 231 | (use-percentage-for-policy? use-percentage-for-policy?) |
| 216 | #:percentage-low percentage-low | 232 | (percentage-low percentage-low) |
| 217 | #:percentage-critical percentage-critical | 233 | (percentage-critical percentage-critical) |
| 218 | #:percentage-action percentage-action | 234 | (percentage-action percentage-action) |
| 219 | #:time-low time-low | 235 | (time-low time-low) |
| 220 | #:time-critical time-critical | 236 | (time-critical time-critical) |
| 221 | #:time-action time-action | 237 | (time-action time-action) |
| 222 | #:critical-power-action critical-power-action))) | 238 | (critical-power-action critical-power-action)))) |
| 223 | (service | 239 | (service upower-service-type config))) |
| 224 | (documentation "Run the UPower power and battery monitor.") | ||
| 225 | (provision '(upower-daemon)) | ||
| 226 | (requirement '(dbus-system udev)) | ||
| 227 | |||
| 228 | (start #~(make-forkexec-constructor | ||
| 229 | (list (string-append #$upower "/libexec/upowerd")) | ||
| 230 | #:environment-variables | ||
| 231 | (list (string-append "UPOWER_CONF_FILE_NAME=" #$config)))) | ||
| 232 | (stop #~(make-kill-destructor)) | ||
| 233 | (activate #~(begin | ||
| 234 | (use-modules (guix build utils)) | ||
| 235 | (mkdir-p "/var/lib/upower") | ||
| 236 | (let ((user (getpwnam "upower"))) | ||
| 237 | (chown "/var/lib/upower" | ||
| 238 | (passwd:uid user) (passwd:gid user))))) | ||
| 239 | |||
| 240 | (user-groups (list (user-group | ||
| 241 | (name "upower") | ||
| 242 | (system? #t)))) | ||
| 243 | (user-accounts (list (user-account | ||
| 244 | (name "upower") | ||
| 245 | (group "upower") | ||
| 246 | (system? #t) | ||
| 247 | (comment "UPower daemon user") | ||
| 248 | (home-directory "/var/empty") | ||
| 249 | (shell | ||
| 250 | #~(string-append #$shadow "/sbin/nologin")))))))) | ||
| 251 | 240 | ||
| 252 | 241 | ||
| 253 | ;;; | 242 | ;;; |
| 254 | ;;; Colord D-Bus service. | 243 | ;;; Colord D-Bus service. |
| 255 | ;;; | 244 | ;;; |
| 256 | 245 | ||
| 246 | (define %colord-activation | ||
| 247 | #~(begin | ||
| 248 | (use-modules (guix build utils)) | ||
| 249 | (mkdir-p "/var/lib/colord") | ||
| 250 | (let ((user (getpwnam "colord"))) | ||
| 251 | (chown "/var/lib/colord" | ||
| 252 | (passwd:uid user) (passwd:gid user))))) | ||
| 253 | |||
| 254 | (define %colord-accounts | ||
| 255 | (list (user-group (name "colord") (system? #t)) | ||
| 256 | (user-account | ||
| 257 | (name "colord") | ||
| 258 | (group "colord") | ||
| 259 | (system? #t) | ||
| 260 | (comment "colord daemon user") | ||
| 261 | (home-directory "/var/empty") | ||
| 262 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 263 | |||
| 264 | (define (colord-dmd-service colord) | ||
| 265 | "Return a dmd service for COLORD." | ||
| 266 | ;; TODO: Remove when D-Bus activation works. | ||
| 267 | (list (dmd-service | ||
| 268 | (documentation "Run the colord color management service.") | ||
| 269 | (provision '(colord-daemon)) | ||
| 270 | (requirement '(dbus-system udev)) | ||
| 271 | (start #~(make-forkexec-constructor | ||
| 272 | (list (string-append #$colord "/libexec/colord")))) | ||
| 273 | (stop #~(make-kill-destructor))))) | ||
| 274 | |||
| 275 | (define colord-service-type | ||
| 276 | (service-type (name 'colord) | ||
| 277 | (extensions | ||
| 278 | (list (service-extension account-service-type | ||
| 279 | (const %colord-accounts)) | ||
| 280 | (service-extension activation-service-type | ||
| 281 | (const %colord-activation)) | ||
| 282 | (service-extension dmd-root-service-type | ||
| 283 | colord-dmd-service) | ||
| 284 | |||
| 285 | ;; Colord is a D-Bus service that dbus-daemon can | ||
| 286 | ;; activate. | ||
| 287 | (service-extension dbus-root-service-type list) | ||
| 288 | |||
| 289 | ;; Colord provides "color device" rules for udev. | ||
| 290 | (service-extension udev-service-type list))))) | ||
| 291 | |||
| 257 | (define* (colord-service #:key (colord colord)) | 292 | (define* (colord-service #:key (colord colord)) |
| 258 | "Return a service that runs @command{colord}, a system service with a D-Bus | 293 | "Return a service that runs @command{colord}, a system service with a D-Bus |
| 259 | interface to manage the color profiles of input and output devices such as | 294 | interface to manage the color profiles of input and output devices such as |
| 260 | screens and scanners. It is notably used by the GNOME Color Manager graphical | 295 | screens and scanners. It is notably used by the GNOME Color Manager graphical |
| 261 | tool. See @uref{http://www.freedesktop.org/software/colord/, the colord web | 296 | tool. See @uref{http://www.freedesktop.org/software/colord/, the colord web |
| 262 | site} for more information." | 297 | site} for more information." |
| 263 | (service | 298 | (service colord-service-type colord)) |
| 264 | (documentation "Run the colord color management service.") | ||
| 265 | (provision '(colord-daemon)) | ||
| 266 | (requirement '(dbus-system udev)) | ||
| 267 | |||
| 268 | (start #~(make-forkexec-constructor | ||
| 269 | (list (string-append #$colord "/libexec/colord")))) | ||
| 270 | (stop #~(make-kill-destructor)) | ||
| 271 | (activate #~(begin | ||
| 272 | (use-modules (guix build utils)) | ||
| 273 | (mkdir-p "/var/lib/colord") | ||
| 274 | (let ((user (getpwnam "colord"))) | ||
| 275 | (chown "/var/lib/colord" | ||
| 276 | (passwd:uid user) (passwd:gid user))))) | ||
| 277 | |||
| 278 | (user-groups (list (user-group | ||
| 279 | (name "colord") | ||
| 280 | (system? #t)))) | ||
| 281 | (user-accounts (list (user-account | ||
| 282 | (name "colord") | ||
| 283 | (group "colord") | ||
| 284 | (system? #t) | ||
| 285 | (comment "colord daemon user") | ||
| 286 | (home-directory "/var/empty") | ||
| 287 | (shell | ||
| 288 | #~(string-append #$shadow "/sbin/nologin"))))))) | ||
| 289 | 299 | ||
| 290 | 300 | ||
| 291 | ;;; | 301 | ;;; |
| 292 | ;;; GeoClue D-Bus service. | 302 | ;;; GeoClue D-Bus service. |
| 293 | ;;; | 303 | ;;; |
| 294 | 304 | ||
| 305 | ;; TODO: Export. | ||
| 306 | (define-record-type* <geoclue-configuration> | ||
| 307 | geoclue-configuration make-geoclue-configuration | ||
| 308 | geoclue-configuration? | ||
| 309 | (geoclue geoclue-configuration-geoclue | ||
| 310 | (default geoclue)) | ||
| 311 | (whitelist geoclue-configuration-whitelist) | ||
| 312 | (wifi-geolocation-url geoclue-configuration-wifi-geolocation-url) | ||
| 313 | (submit-data? geoclue-configuration-submit-data?) | ||
| 314 | (wifi-submission-url geoclue-configuration-wifi-submission-url) | ||
| 315 | (submission-nick geoclue-configuration-submission-nick) | ||
| 316 | (applications geoclue-configuration-applications)) | ||
| 317 | |||
| 295 | (define* (geoclue-application name #:key (allowed? #t) system? (users '())) | 318 | (define* (geoclue-application name #:key (allowed? #t) system? (users '())) |
| 296 | "Configure default GeoClue access permissions for an application. NAME is | 319 | "Configure default GeoClue access permissions for an application. NAME is |
| 297 | the Desktop ID of the application, without the .desktop part. If ALLOWED? is | 320 | the Desktop ID of the application, without the .desktop part. If ALLOWED? is |
| @@ -311,21 +334,67 @@ users are allowed." | |||
| 311 | (geoclue-application "epiphany" #:system? #f) | 334 | (geoclue-application "epiphany" #:system? #f) |
| 312 | (geoclue-application "firefox" #:system? #f))) | 335 | (geoclue-application "firefox" #:system? #f))) |
| 313 | 336 | ||
| 314 | (define* (geoclue-configuration-file #:key whitelist wifi-geolocation-url | 337 | (define* (geoclue-configuration-file config) |
| 315 | submit-data? | ||
| 316 | wifi-submission-url submission-nick | ||
| 317 | applications) | ||
| 318 | "Return a geoclue configuration file." | 338 | "Return a geoclue configuration file." |
| 319 | (plain-file "geoclue.conf" | 339 | (plain-file "geoclue.conf" |
| 320 | (string-append | 340 | (string-append |
| 321 | "[agent]\n" | 341 | "[agent]\n" |
| 322 | "whitelist=" (string-join whitelist ";") "\n" | 342 | "whitelist=" |
| 343 | (string-join (geoclue-configuration-whitelist config) | ||
| 344 | ";") "\n" | ||
| 323 | "[wifi]\n" | 345 | "[wifi]\n" |
| 324 | "url=" wifi-geolocation-url "\n" | 346 | "url=" (geoclue-configuration-wifi-geolocation-url config) "\n" |
| 325 | "submit-data=" (bool submit-data?) | 347 | "submit-data=" (bool (geoclue-configuration-submit-data? config)) |
| 326 | "submission-url=" wifi-submission-url "\n" | 348 | "submission-url=" |
| 327 | "submission-nick=" submission-nick "\n" | 349 | (geoclue-configuration-wifi-submission-url config) "\n" |
| 328 | (string-join applications "\n")))) | 350 | "submission-nick=" |
| 351 | (geoclue-configuration-submission-nick config) | ||
| 352 | "\n" | ||
| 353 | (string-join (geoclue-configuration-applications config) | ||
| 354 | "\n")))) | ||
| 355 | |||
| 356 | (define (geoclue-dbus-service config) | ||
| 357 | (list (wrapped-dbus-service (geoclue-configuration-geoclue config) | ||
| 358 | "libexec/geoclue" | ||
| 359 | "GEOCLUE_CONFIG_FILE" | ||
| 360 | (geoclue-configuration-file config)))) | ||
| 361 | |||
| 362 | (define (geoclue-dmd-service config) | ||
| 363 | "Return a GeoClue dmd service for CONFIG." | ||
| 364 | ;; TODO: Remove when D-Bus activation works. | ||
| 365 | (let ((geoclue (geoclue-configuration-geoclue config)) | ||
| 366 | (config (geoclue-configuration-file config))) | ||
| 367 | (list (dmd-service | ||
| 368 | (documentation "Run the GeoClue location service.") | ||
| 369 | (provision '(geoclue-daemon)) | ||
| 370 | (requirement '(dbus-system)) | ||
| 371 | |||
| 372 | (start #~(make-forkexec-constructor | ||
| 373 | (list (string-append #$geoclue "/libexec/geoclue")) | ||
| 374 | #:user "geoclue" | ||
| 375 | #:environment-variables | ||
| 376 | (list (string-append "GEOCLUE_CONFIG_FILE=" #$config)))) | ||
| 377 | (stop #~(make-kill-destructor)))))) | ||
| 378 | |||
| 379 | (define %geoclue-accounts | ||
| 380 | (list (user-group (name "geoclue") (system? #t)) | ||
| 381 | (user-account | ||
| 382 | (name "geoclue") | ||
| 383 | (group "geoclue") | ||
| 384 | (system? #t) | ||
| 385 | (comment "GeoClue daemon user") | ||
| 386 | (home-directory "/var/empty") | ||
| 387 | (shell "/run/current-system/profile/sbin/nologin")))) | ||
| 388 | |||
| 389 | (define geoclue-service-type | ||
| 390 | (service-type (name 'geoclue) | ||
| 391 | (extensions | ||
| 392 | (list (service-extension dbus-root-service-type | ||
| 393 | geoclue-dbus-service) | ||
| 394 | (service-extension dmd-root-service-type | ||
| 395 | geoclue-dmd-service) | ||
| 396 | (service-extension account-service-type | ||
| 397 | (const %geoclue-accounts)))))) | ||
| 329 | 398 | ||
| 330 | (define* (geoclue-service #:key (geoclue geoclue) | 399 | (define* (geoclue-service #:key (geoclue geoclue) |
| 331 | (whitelist '()) | 400 | (whitelist '()) |
| @@ -345,70 +414,67 @@ and Epiphany web browsers are able to ask for the user's location, and in the | |||
| 345 | case of Icecat and Epiphany, both will ask the user for permission first. See | 414 | case of Icecat and Epiphany, both will ask the user for permission first. See |
| 346 | @uref{https://wiki.freedesktop.org/www/Software/GeoClue/, the geoclue web | 415 | @uref{https://wiki.freedesktop.org/www/Software/GeoClue/, the geoclue web |
| 347 | site} for more information." | 416 | site} for more information." |
| 348 | (let ((config (geoclue-configuration-file | 417 | (service geoclue-service-type |
| 349 | #:whitelist whitelist | 418 | (geoclue-configuration |
| 350 | #:wifi-geolocation-url wifi-geolocation-url | 419 | (geoclue geoclue) |
| 351 | #:submit-data? submit-data? | 420 | (whitelist whitelist) |
| 352 | #:wifi-submission-url wifi-submission-url | 421 | (wifi-geolocation-url wifi-geolocation-url) |
| 353 | #:submission-nick submission-nick | 422 | (submit-data? submit-data?) |
| 354 | #:applications applications))) | 423 | (wifi-submission-url wifi-submission-url) |
| 355 | (service | 424 | (submission-nick submission-nick) |
| 356 | (documentation "Run the GeoClue location service.") | 425 | (applications applications)))) |
| 357 | (provision '(geoclue-daemon)) | ||
| 358 | (requirement '(dbus-system)) | ||
| 359 | |||
| 360 | (start #~(make-forkexec-constructor | ||
| 361 | (list (string-append #$geoclue "/libexec/geoclue")) | ||
| 362 | #:user "geoclue" | ||
| 363 | #:environment-variables | ||
| 364 | (list (string-append "GEOCLUE_CONFIG_FILE=" #$config)))) | ||
| 365 | (stop #~(make-kill-destructor)) | ||
| 366 | |||
| 367 | (user-groups (list (user-group | ||
| 368 | (name "geoclue") | ||
| 369 | (system? #t)))) | ||
| 370 | (user-accounts (list (user-account | ||
| 371 | (name "geoclue") | ||
| 372 | (group "geoclue") | ||
| 373 | (system? #t) | ||
| 374 | (comment "GeoClue daemon user") | ||
| 375 | (home-directory "/var/empty") | ||
| 376 | (shell | ||
| 377 | "/run/current-system/profile/sbin/nologin"))))))) | ||
| 378 | 426 | ||
| 379 | 427 | ||
| 380 | ;;; | 428 | ;;; |
| 381 | ;;; Polkit privilege management service. | 429 | ;;; Polkit privilege management service. |
| 382 | ;;; | 430 | ;;; |
| 383 | 431 | ||
| 432 | (define %polkit-accounts | ||
| 433 | (list (user-group (name "polkitd") (system? #t)) | ||
| 434 | (user-account | ||
| 435 | (name "polkitd") | ||
| 436 | (group "polkitd") | ||
| 437 | (system? #t) | ||
| 438 | (comment "Polkit daemon user") | ||
| 439 | (home-directory "/var/empty") | ||
| 440 | (shell "/run/current-system/profile/sbin/nologin")))) | ||
| 441 | |||
| 442 | (define %polkit-pam-services | ||
| 443 | (list (unix-pam-service "polkit-1"))) | ||
| 444 | |||
| 445 | (define (polkit-dmd-service polkit) | ||
| 446 | "Return the <dmd-service> for POLKIT." | ||
| 447 | ;; TODO: Remove when D-Bus activation works. | ||
| 448 | (list (dmd-service | ||
| 449 | (documentation "Run the polkit privilege management service.") | ||
| 450 | (provision '(polkit-daemon)) | ||
| 451 | (requirement '(dbus-system)) | ||
| 452 | |||
| 453 | (start #~(make-forkexec-constructor | ||
| 454 | (list (string-append #$polkit "/lib/polkit-1/polkitd")))) | ||
| 455 | (stop #~(make-kill-destructor))))) | ||
| 456 | |||
| 457 | (define polkit-service-type | ||
| 458 | ;; TODO: Make it extensible so it can collect policy files from other | ||
| 459 | ;; services. | ||
| 460 | (service-type (name 'polkit) | ||
| 461 | (extensions | ||
| 462 | (list (service-extension account-service-type | ||
| 463 | (const %polkit-accounts)) | ||
| 464 | (service-extension pam-root-service-type | ||
| 465 | (const %polkit-pam-services)) | ||
| 466 | (service-extension dbus-root-service-type | ||
| 467 | list) | ||
| 468 | (service-extension dmd-root-service-type | ||
| 469 | polkit-dmd-service))))) | ||
| 470 | |||
| 384 | (define* (polkit-service #:key (polkit polkit)) | 471 | (define* (polkit-service #:key (polkit polkit)) |
| 385 | "Return a service that runs the @command{polkit} privilege management | 472 | "Return a service that runs the @command{polkit} privilege management |
| 386 | service. By querying the @command{polkit} service, a privileged system | 473 | service. By querying the @command{polkit} service, a privileged system |
| 387 | component can know when it should grant additional capabilities to ordinary | 474 | component can know when it should grant additional capabilities to ordinary |
| 388 | users. For example, an ordinary user can be granted the capability to suspend | 475 | users. For example, an ordinary user can be granted the capability to suspend |
| 389 | the system if the user is logged in locally." | 476 | the system if the user is logged in locally." |
| 390 | (service | 477 | (service polkit-service-type polkit)) |
| 391 | (documentation "Run the polkit privilege management service.") | ||
| 392 | (provision '(polkit-daemon)) | ||
| 393 | (requirement '(dbus-system)) | ||
| 394 | |||
| 395 | (start #~(make-forkexec-constructor | ||
| 396 | (list (string-append #$polkit "/lib/polkit-1/polkitd")))) | ||
| 397 | (stop #~(make-kill-destructor)) | ||
| 398 | |||
| 399 | (user-groups (list (user-group | ||
| 400 | (name "polkitd") | ||
| 401 | (system? #t)))) | ||
| 402 | (user-accounts (list (user-account | ||
| 403 | (name "polkitd") | ||
| 404 | (group "polkitd") | ||
| 405 | (system? #t) | ||
| 406 | (comment "Polkit daemon user") | ||
| 407 | (home-directory "/var/empty") | ||
| 408 | (shell | ||
| 409 | "/run/current-system/profile/sbin/nologin")))) | ||
| 410 | |||
| 411 | (pam-services (list (unix-pam-service "polkit-1"))))) | ||
| 412 | 478 | ||
| 413 | 479 | ||
| 414 | ;;; | 480 | ;;; |
| @@ -418,6 +484,8 @@ the system if the user is logged in locally." | |||
| 418 | (define-record-type* <elogind-configuration> elogind-configuration | 484 | (define-record-type* <elogind-configuration> elogind-configuration |
| 419 | make-elogind-configuration | 485 | make-elogind-configuration |
| 420 | elogind-configuration | 486 | elogind-configuration |
| 487 | (elogind elogind-package | ||
| 488 | (default elogind)) | ||
| 421 | (kill-user-processes? elogind-kill-user-processes? | 489 | (kill-user-processes? elogind-kill-user-processes? |
| 422 | (default #f)) | 490 | (default #f)) |
| 423 | (kill-only-users elogind-kill-only-users | 491 | (kill-only-users elogind-kill-only-users |
| @@ -547,67 +615,62 @@ the system if the user is logged in locally." | |||
| 547 | ("HybridSleepState" (sleep-list elogind-hybrid-sleep-state)) | 615 | ("HybridSleepState" (sleep-list elogind-hybrid-sleep-state)) |
| 548 | ("HybridSleepMode" (sleep-list elogind-hybrid-sleep-mode)))) | 616 | ("HybridSleepMode" (sleep-list elogind-hybrid-sleep-mode)))) |
| 549 | 617 | ||
| 550 | (define* (elogind-service #:key (elogind elogind) | 618 | (define (elogind-dmd-service config) |
| 551 | (config (elogind-configuration))) | 619 | "Return a dmd service for elogind, using @var{config}." |
| 620 | (let ((config-file (elogind-configuration-file config)) | ||
| 621 | (elogind (elogind-package config))) | ||
| 622 | (list (dmd-service | ||
| 623 | (documentation "Run the elogind login and seat management service.") | ||
| 624 | (provision '(elogind)) | ||
| 625 | (requirement '(dbus-system)) | ||
| 626 | |||
| 627 | (start #~(make-forkexec-constructor | ||
| 628 | (list (string-append #$elogind "/libexec/elogind/elogind")) | ||
| 629 | #:environment-variables | ||
| 630 | (list (string-append "ELOGIND_CONF_FILE=" #$config-file)))) | ||
| 631 | (stop #~(make-kill-destructor)))))) | ||
| 632 | |||
| 633 | (define elogind-service-type | ||
| 634 | (service-type (name 'elogind) | ||
| 635 | (extensions | ||
| 636 | (list (service-extension dmd-root-service-type | ||
| 637 | elogind-dmd-service) | ||
| 638 | (service-extension dbus-root-service-type | ||
| 639 | (compose list elogind-package)) | ||
| 640 | (service-extension udev-service-type | ||
| 641 | (compose list elogind-package)) | ||
| 642 | ;; TODO: Extend polkit(?) and PAM. | ||
| 643 | )))) | ||
| 644 | |||
| 645 | (define* (elogind-service #:key (config (elogind-configuration))) | ||
| 552 | "Return a service that runs the @command{elogind} login and seat management | 646 | "Return a service that runs the @command{elogind} login and seat management |
| 553 | service. The @command{elogind} service integrates with PAM to allow other | 647 | service. The @command{elogind} service integrates with PAM to allow other |
| 554 | system components to know the set of logged-in users as well as their session | 648 | system components to know the set of logged-in users as well as their session |
| 555 | types (graphical, console, remote, etc.). It can also clean up after users | 649 | types (graphical, console, remote, etc.). It can also clean up after users |
| 556 | when they log out." | 650 | when they log out." |
| 557 | (let ((config-file (elogind-configuration-file config))) | 651 | (service elogind-service-type config)) |
| 558 | (service | ||
| 559 | (documentation "Run the elogind login and seat management service.") | ||
| 560 | (provision '(elogind)) | ||
| 561 | (requirement '(dbus-system)) | ||
| 562 | |||
| 563 | (start #~(make-forkexec-constructor | ||
| 564 | (list (string-append #$elogind "/libexec/elogind/elogind")) | ||
| 565 | #:environment-variables | ||
| 566 | (list (string-append "ELOGIND_CONF_FILE=" #$config-file)))) | ||
| 567 | (stop #~(make-kill-destructor))))) | ||
| 568 | 652 | ||
| 569 | 653 | ||
| 570 | ;;; | 654 | ;;; |
| 571 | ;;; The default set of desktop services. | 655 | ;;; The default set of desktop services. |
| 572 | ;;; | 656 | ;;; |
| 657 | |||
| 573 | (define %desktop-services | 658 | (define %desktop-services |
| 574 | ;; List of services typically useful for a "desktop" use case. | 659 | ;; List of services typically useful for a "desktop" use case. |
| 575 | (cons* (slim-service) | 660 | (cons* (slim-service) |
| 576 | 661 | ||
| 662 | ;; The D-Bus clique. | ||
| 577 | (avahi-service) | 663 | (avahi-service) |
| 578 | (wicd-service) | 664 | (wicd-service) |
| 579 | (upower-service) | 665 | (upower-service) |
| 580 | ;; FIXME: The colord, geoclue, and polkit services could all be | ||
| 581 | ;; bus-activated by default, so they don't run at program startup. | ||
| 582 | ;; However, user creation and /var/lib/colord creation happen at | ||
| 583 | ;; service activation time, so we currently add them to the set of | ||
| 584 | ;; default services. | ||
| 585 | (colord-service) | 666 | (colord-service) |
| 586 | (geoclue-service) | 667 | (geoclue-service) |
| 587 | (polkit-service) | 668 | (polkit-service) |
| 588 | (elogind-service) | 669 | (elogind-service) |
| 589 | (dbus-service (list avahi wicd upower colord geoclue polkit elogind)) | 670 | (dbus-service) |
| 590 | 671 | ||
| 591 | (ntp-service) | 672 | (ntp-service) |
| 592 | 673 | ||
| 593 | (map (lambda (service) | 674 | %base-services)) |
| 594 | (cond | ||
| 595 | ;; Provide an nscd ready to use nss-mdns. | ||
| 596 | ((memq 'nscd (service-provision service)) | ||
| 597 | (nscd-service (nscd-configuration | ||
| 598 | (name-services (list nss-mdns))))) | ||
| 599 | |||
| 600 | ;; Add more rules to udev-service. | ||
| 601 | ;; | ||
| 602 | ;; XXX Keep this in sync with the 'udev-service' call in | ||
| 603 | ;; %base-services. Here we intend only to add 'upower', | ||
| 604 | ;; 'colord', and 'elogind'. | ||
| 605 | ((memq 'udev (service-provision service)) | ||
| 606 | (udev-service #:rules | ||
| 607 | (list lvm2 fuse alsa-utils crda | ||
| 608 | upower colord elogind))) | ||
| 609 | |||
| 610 | (else service))) | ||
| 611 | %base-services))) | ||
| 612 | 675 | ||
| 613 | ;;; desktop.scm ends here | 676 | ;;; desktop.scm ends here |
diff --git a/gnu/services/dmd.scm b/gnu/services/dmd.scm index 618df91c5e3..6020ffc8ebf 100644 --- a/gnu/services/dmd.scm +++ b/gnu/services/dmd.scm | |||
| @@ -22,13 +22,27 @@ | |||
| 22 | #:use-module (guix gexp) | 22 | #:use-module (guix gexp) |
| 23 | #:use-module (guix store) | 23 | #:use-module (guix store) |
| 24 | #:use-module (guix monads) | 24 | #:use-module (guix monads) |
| 25 | #:use-module (guix records) | ||
| 25 | #:use-module (guix derivations) ;imported-modules, etc. | 26 | #:use-module (guix derivations) ;imported-modules, etc. |
| 26 | #:use-module (gnu services) | 27 | #:use-module (gnu services) |
| 28 | #:use-module (gnu packages admin) | ||
| 27 | #:use-module (ice-9 match) | 29 | #:use-module (ice-9 match) |
| 28 | #:use-module (srfi srfi-1) | 30 | #:use-module (srfi srfi-1) |
| 29 | #:use-module (srfi srfi-34) | 31 | #:use-module (srfi srfi-34) |
| 30 | #:use-module (srfi srfi-35) | 32 | #:use-module (srfi srfi-35) |
| 31 | #:export (dmd-configuration-file)) | 33 | #:export (dmd-root-service-type |
| 34 | %dmd-root-service | ||
| 35 | dmd-service-type | ||
| 36 | |||
| 37 | dmd-service | ||
| 38 | dmd-service? | ||
| 39 | dmd-service-documentation | ||
| 40 | dmd-service-provision | ||
| 41 | dmd-service-requirement | ||
| 42 | dmd-service-respawn? | ||
| 43 | dmd-service-start | ||
| 44 | dmd-service-stop | ||
| 45 | dmd-service-auto-start?)) | ||
| 32 | 46 | ||
| 33 | ;;; Commentary: | 47 | ;;; Commentary: |
| 34 | ;;; | 48 | ;;; |
| @@ -36,6 +50,68 @@ | |||
| 36 | ;;; | 50 | ;;; |
| 37 | ;;; Code: | 51 | ;;; Code: |
| 38 | 52 | ||
| 53 | |||
| 54 | (define (dmd-boot-gexp services) | ||
| 55 | (mlet %store-monad ((dmd-conf (dmd-configuration-file services))) | ||
| 56 | (return #~(begin | ||
| 57 | ;; Keep track of the booted system. | ||
| 58 | (false-if-exception (delete-file "/run/booted-system")) | ||
| 59 | (symlink (readlink "/run/current-system") | ||
| 60 | "/run/booted-system") | ||
| 61 | |||
| 62 | ;; Close any remaining open file descriptors to be on the safe | ||
| 63 | ;; side. This must be the very last thing we do, because | ||
| 64 | ;; Guile has internal FDs such as 'sleep_pipe' that need to be | ||
| 65 | ;; alive. | ||
| 66 | (let loop ((fd 3)) | ||
| 67 | (when (< fd 1024) | ||
| 68 | (false-if-exception (close-fdes fd)) | ||
| 69 | (loop (+ 1 fd)))) | ||
| 70 | |||
| 71 | ;; Start dmd. | ||
| 72 | (execl (string-append #$dmd "/bin/dmd") | ||
| 73 | "dmd" "--config" #$dmd-conf))))) | ||
| 74 | |||
| 75 | (define dmd-root-service-type | ||
| 76 | (service-type | ||
| 77 | (name 'dmd-root) | ||
| 78 | ;; Extending the root dmd service (aka. PID 1) happens by concatenating the | ||
| 79 | ;; list of services provided by the extensions. | ||
| 80 | (compose concatenate) | ||
| 81 | (extend append) | ||
| 82 | (extensions (list (service-extension boot-service-type dmd-boot-gexp))))) | ||
| 83 | |||
| 84 | (define %dmd-root-service | ||
| 85 | ;; The root dmd service, aka. PID 1. Its parameter is a list of | ||
| 86 | ;; <dmd-service> objects. | ||
| 87 | (service dmd-root-service-type '())) | ||
| 88 | |||
| 89 | (define-syntax-rule (dmd-service-type proc) | ||
| 90 | "Return a <service-type> denoting a simple dmd service--i.e., the type for a | ||
| 91 | service that extends DMD-ROOT-SERVICE-TYPE and nothing else." | ||
| 92 | (service-type | ||
| 93 | (name 'some-dmd-service) | ||
| 94 | (extensions | ||
| 95 | (list (service-extension dmd-root-service-type | ||
| 96 | (compose list proc)))))) | ||
| 97 | |||
| 98 | (define-record-type* <dmd-service> | ||
| 99 | dmd-service make-dmd-service | ||
| 100 | dmd-service? | ||
| 101 | (documentation service-documentation ; string | ||
| 102 | (default "[No documentation.]")) | ||
| 103 | (provision service-provision) ; list of symbols | ||
| 104 | (requirement service-requirement ; list of symbols | ||
| 105 | (default '())) | ||
| 106 | (respawn? service-respawn? ; Boolean | ||
| 107 | (default #t)) | ||
| 108 | (start service-start) ; g-expression (procedure) | ||
| 109 | (stop service-stop ; g-expression (procedure) | ||
| 110 | (default #~(const #f))) | ||
| 111 | (auto-start? service-auto-start? ; Boolean | ||
| 112 | (default #t))) | ||
| 113 | |||
| 114 | |||
| 39 | (define (assert-no-duplicates services) | 115 | (define (assert-no-duplicates services) |
| 40 | "Raise an error if SERVICES provide the same dmd service more than once. | 116 | "Raise an error if SERVICES provide the same dmd service more than once. |
| 41 | 117 | ||
diff --git a/gnu/services/lirc.scm b/gnu/services/lirc.scm index 368f2ba2937..6ae622579d7 100644 --- a/gnu/services/lirc.scm +++ b/gnu/services/lirc.scm | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2015 Alex Kost <alezost@gmail.com> | 2 | ;;; Copyright © 2015 Alex Kost <alezost@gmail.com> |
| 3 | ;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | ;;; | 4 | ;;; |
| 4 | ;;; This file is part of GNU Guix. | 5 | ;;; This file is part of GNU Guix. |
| 5 | ;;; | 6 | ;;; |
| @@ -18,17 +19,65 @@ | |||
| 18 | 19 | ||
| 19 | (define-module (gnu services lirc) | 20 | (define-module (gnu services lirc) |
| 20 | #:use-module (gnu services) | 21 | #:use-module (gnu services) |
| 22 | #:use-module (gnu services dmd) | ||
| 21 | #:use-module (gnu packages lirc) | 23 | #:use-module (gnu packages lirc) |
| 22 | #:use-module (guix store) | ||
| 23 | #:use-module (guix gexp) | 24 | #:use-module (guix gexp) |
| 25 | #:use-module (guix records) | ||
| 26 | #:use-module (ice-9 match) | ||
| 24 | #:export (lirc-service)) | 27 | #:export (lirc-service)) |
| 25 | 28 | ||
| 26 | ;;; Commentary: | 29 | ;;; Commentary: |
| 27 | ;;; | 30 | ;;; |
| 28 | ;;; LIRC services. | 31 | ;;; LIRC service. |
| 29 | ;;; | 32 | ;;; |
| 30 | ;;; Code: | 33 | ;;; Code: |
| 31 | 34 | ||
| 35 | (define-record-type* <lirc-configuration> | ||
| 36 | lirc-configuration make-lirc-configuration | ||
| 37 | lirc-configuation? | ||
| 38 | (lirc lirc-configuration-lirc ;<package> | ||
| 39 | (default lirc)) | ||
| 40 | (device lirc-configuration-device) ;string | ||
| 41 | (driver lirc-configuration-driver) ;string | ||
| 42 | (config-file lirc-configuration-file) ;string | file-like object | ||
| 43 | (extra-options lirc-configuration-options ;list of strings | ||
| 44 | (default '()))) | ||
| 45 | |||
| 46 | (define %lirc-activation | ||
| 47 | #~(begin | ||
| 48 | (use-modules (guix build utils)) | ||
| 49 | (mkdir-p "/var/run/lirc"))) | ||
| 50 | |||
| 51 | (define lirc-dmd-service | ||
| 52 | (match-lambda | ||
| 53 | (($ <lirc-configuration> lirc device driver config-file options) | ||
| 54 | (list (dmd-service | ||
| 55 | (provision '(lircd)) | ||
| 56 | (documentation "Run the LIRC daemon.") | ||
| 57 | (requirement '(user-processes)) | ||
| 58 | (start #~(make-forkexec-constructor | ||
| 59 | (list (string-append #$lirc "/sbin/lircd") | ||
| 60 | "--nodaemon" | ||
| 61 | #$@(if device | ||
| 62 | #~("--device" #$device) | ||
| 63 | #~()) | ||
| 64 | #$@(if driver | ||
| 65 | #~("--driver" #$driver) | ||
| 66 | #~()) | ||
| 67 | #$@(if config-file | ||
| 68 | #~(#$config-file) | ||
| 69 | #~()) | ||
| 70 | #$@options))) | ||
| 71 | (stop #~(make-kill-destructor))))))) | ||
| 72 | |||
| 73 | (define lirc-service-type | ||
| 74 | (service-type (name 'lirc) | ||
| 75 | (extensions | ||
| 76 | (list (service-extension dmd-root-service-type | ||
| 77 | lirc-dmd-service) | ||
| 78 | (service-extension activation-service-type | ||
| 79 | (const %lirc-activation)))))) | ||
| 80 | |||
| 32 | (define* (lirc-service #:key (lirc lirc) | 81 | (define* (lirc-service #:key (lirc lirc) |
| 33 | device driver config-file | 82 | device driver config-file |
| 34 | (extra-options '())) | 83 | (extra-options '())) |
| @@ -40,26 +89,11 @@ The daemon will use specified @var{device}, @var{driver} and | |||
| 40 | 89 | ||
| 41 | Finally, @var{extra-options} is a list of additional command-line options | 90 | Finally, @var{extra-options} is a list of additional command-line options |
| 42 | passed to @command{lircd}." | 91 | passed to @command{lircd}." |
| 43 | (service | 92 | (service lirc-service-type |
| 44 | (provision '(lircd)) | 93 | (lirc-configuration |
| 45 | (documentation "Run the LIRC daemon.") | 94 | (lirc lirc) |
| 46 | (requirement '(user-processes)) | 95 | (device device) (driver driver) |
| 47 | (start #~(make-forkexec-constructor | 96 | (config-file config-file) |
| 48 | (list (string-append #$lirc "/sbin/lircd") | 97 | (extra-options extra-options)))) |
| 49 | "--nodaemon" | ||
| 50 | #$@(if device | ||
| 51 | #~("--device" #$device) | ||
| 52 | #~()) | ||
| 53 | #$@(if driver | ||
| 54 | #~("--driver" #$driver) | ||
| 55 | #~()) | ||
| 56 | #$@(if config-file | ||
| 57 | #~(#$config-file) | ||
| 58 | #~()) | ||
| 59 | #$@extra-options))) | ||
| 60 | (stop #~(make-kill-destructor)) | ||
| 61 | (activate #~(begin | ||
| 62 | (use-modules (guix build utils)) | ||
| 63 | (mkdir-p "/var/run/lirc"))))) | ||
| 64 | 98 | ||
| 65 | ;;; lirc.scm ends here | 99 | ;;; lirc.scm ends here |
diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index 50ffac57962..52a843b54b2 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm | |||
| @@ -19,7 +19,10 @@ | |||
| 19 | 19 | ||
| 20 | (define-module (gnu services networking) | 20 | (define-module (gnu services networking) |
| 21 | #:use-module (gnu services) | 21 | #:use-module (gnu services) |
| 22 | #:use-module (gnu services dmd) | ||
| 23 | #:use-module (gnu services dbus) | ||
| 22 | #:use-module (gnu system shadow) | 24 | #:use-module (gnu system shadow) |
| 25 | #:use-module (gnu system linux) ;PAM | ||
| 23 | #:use-module (gnu packages admin) | 26 | #:use-module (gnu packages admin) |
| 24 | #:use-module (gnu packages linux) | 27 | #:use-module (gnu packages linux) |
| 25 | #:use-module (gnu packages tor) | 28 | #:use-module (gnu packages tor) |
| @@ -27,8 +30,9 @@ | |||
| 27 | #:use-module (gnu packages ntp) | 30 | #:use-module (gnu packages ntp) |
| 28 | #:use-module (gnu packages wicd) | 31 | #:use-module (gnu packages wicd) |
| 29 | #:use-module (guix gexp) | 32 | #:use-module (guix gexp) |
| 30 | #:use-module (guix store) | 33 | #:use-module (guix records) |
| 31 | #:use-module (srfi srfi-26) | 34 | #:use-module (srfi srfi-26) |
| 35 | #:use-module (ice-9 match) | ||
| 32 | #:export (%facebook-host-aliases | 36 | #:export (%facebook-host-aliases |
| 33 | static-networking-service | 37 | static-networking-service |
| 34 | dhcp-client-service | 38 | dhcp-client-service |
| @@ -78,6 +82,72 @@ fe80::1%lo0 www.connect.facebook.net | |||
| 78 | fe80::1%lo0 apps.facebook.com\n") | 82 | fe80::1%lo0 apps.facebook.com\n") |
| 79 | 83 | ||
| 80 | 84 | ||
| 85 | (define-record-type* <static-networking> | ||
| 86 | static-networking make-static-networking | ||
| 87 | static-networking? | ||
| 88 | (interface static-networking-interface) | ||
| 89 | (ip static-networking-ip) | ||
| 90 | (gateway static-networking-gateway) | ||
| 91 | (provision static-networking-provision) | ||
| 92 | (name-servers static-networking-name-servers) | ||
| 93 | (net-tools static-networking-net-tools)) | ||
| 94 | |||
| 95 | (define static-networking-service-type | ||
| 96 | (dmd-service-type | ||
| 97 | (match-lambda | ||
| 98 | (($ <static-networking> interface ip gateway provision | ||
| 99 | name-servers net-tools) | ||
| 100 | (let ((loopback? (memq 'loopback provision))) | ||
| 101 | |||
| 102 | ;; TODO: Eventually replace 'route' with bindings for the appropriate | ||
| 103 | ;; ioctls. | ||
| 104 | (dmd-service | ||
| 105 | |||
| 106 | ;; Unless we're providing the loopback interface, wait for udev to be up | ||
| 107 | ;; and running so that INTERFACE is actually usable. | ||
| 108 | (requirement (if loopback? '() '(udev))) | ||
| 109 | |||
| 110 | (documentation | ||
| 111 | "Bring up the networking interface using a static IP address.") | ||
| 112 | (provision provision) | ||
| 113 | (start #~(lambda _ | ||
| 114 | ;; Return #t if successfully started. | ||
| 115 | (let* ((addr (inet-pton AF_INET #$ip)) | ||
| 116 | (sockaddr (make-socket-address AF_INET addr 0))) | ||
| 117 | (configure-network-interface #$interface sockaddr | ||
| 118 | (logior IFF_UP | ||
| 119 | #$(if loopback? | ||
| 120 | #~IFF_LOOPBACK | ||
| 121 | 0)))) | ||
| 122 | #$(if gateway | ||
| 123 | #~(zero? (system* (string-append #$net-tools | ||
| 124 | "/sbin/route") | ||
| 125 | "add" "-net" "default" | ||
| 126 | "gw" #$gateway)) | ||
| 127 | #t) | ||
| 128 | #$(if (pair? name-servers) | ||
| 129 | #~(call-with-output-file "/etc/resolv.conf" | ||
| 130 | (lambda (port) | ||
| 131 | (display | ||
| 132 | "# Generated by 'static-networking-service'.\n" | ||
| 133 | port) | ||
| 134 | (for-each (lambda (server) | ||
| 135 | (format port "nameserver ~a~%" | ||
| 136 | server)) | ||
| 137 | '#$name-servers))) | ||
| 138 | #t))) | ||
| 139 | (stop #~(lambda _ | ||
| 140 | ;; Return #f is successfully stopped. | ||
| 141 | (let ((sock (socket AF_INET SOCK_STREAM 0))) | ||
| 142 | (set-network-interface-flags sock #$interface 0) | ||
| 143 | (close-port sock)) | ||
| 144 | (not #$(if gateway | ||
| 145 | #~(system* (string-append #$net-tools | ||
| 146 | "/sbin/route") | ||
| 147 | "del" "-net" "default") | ||
| 148 | #t)))) | ||
| 149 | (respawn? #f))))))) | ||
| 150 | |||
| 81 | (define* (static-networking-service interface ip | 151 | (define* (static-networking-service interface ip |
| 82 | #:key | 152 | #:key |
| 83 | gateway | 153 | gateway |
| @@ -87,111 +157,70 @@ fe80::1%lo0 apps.facebook.com\n") | |||
| 87 | "Return a service that starts @var{interface} with address @var{ip}. If | 157 | "Return a service that starts @var{interface} with address @var{ip}. If |
| 88 | @var{gateway} is true, it must be a string specifying the default network | 158 | @var{gateway} is true, it must be a string specifying the default network |
| 89 | gateway." | 159 | gateway." |
| 90 | (define loopback? | 160 | (service static-networking-service-type |
| 91 | (memq 'loopback provision)) | 161 | (static-networking (interface interface) (ip ip) |
| 92 | 162 | (gateway gateway) | |
| 93 | ;; TODO: Eventually replace 'route' with bindings for the appropriate | 163 | (provision provision) |
| 94 | ;; ioctls. | 164 | (name-servers name-servers) |
| 95 | (service | 165 | (net-tools net-tools)))) |
| 96 | 166 | ||
| 97 | ;; Unless we're providing the loopback interface, wait for udev to be up | 167 | (define dhcp-client-service-type |
| 98 | ;; and running so that INTERFACE is actually usable. | 168 | (dmd-service-type |
| 99 | (requirement (if loopback? '() '(udev))) | 169 | (lambda (dhcp) |
| 100 | 170 | (define dhclient | |
| 101 | (documentation | 171 | #~(string-append #$dhcp "/sbin/dhclient")) |
| 102 | "Bring up the networking interface using a static IP address.") | 172 | |
| 103 | (provision provision) | 173 | (define pid-file |
| 104 | (start #~(lambda _ | 174 | "/var/run/dhclient.pid") |
| 105 | ;; Return #t if successfully started. | 175 | |
| 106 | (let* ((addr (inet-pton AF_INET #$ip)) | 176 | (dmd-service |
| 107 | (sockaddr (make-socket-address AF_INET addr 0))) | 177 | (documentation "Set up networking via DHCP.") |
| 108 | (configure-network-interface #$interface sockaddr | 178 | (requirement '(user-processes udev)) |
| 109 | (logior IFF_UP | 179 | |
| 110 | #$(if loopback? | 180 | ;; XXX: Running with '-nw' ("no wait") avoids blocking for a minute when |
| 111 | #~IFF_LOOPBACK | 181 | ;; networking is unavailable, but also means that the interface is not up |
| 112 | 0)))) | 182 | ;; yet when 'start' completes. To wait for the interface to be ready, one |
| 113 | #$(if gateway | 183 | ;; should instead monitor udev events. |
| 114 | #~(zero? (system* (string-append #$net-tools | 184 | (provision '(networking)) |
| 115 | "/sbin/route") | 185 | |
| 116 | "add" "-net" "default" | 186 | (start #~(lambda _ |
| 117 | "gw" #$gateway)) | 187 | ;; When invoked without any arguments, 'dhclient' discovers all |
| 118 | #t) | 188 | ;; non-loopback interfaces *that are up*. However, the relevant |
| 119 | #$(if (pair? name-servers) | 189 | ;; interfaces are typically down at this point. Thus we perform |
| 120 | #~(call-with-output-file "/etc/resolv.conf" | 190 | ;; our own interface discovery here. |
| 121 | (lambda (port) | 191 | (define valid? |
| 122 | (display | 192 | (negate loopback-network-interface?)) |
| 123 | "# Generated by 'static-networking-service'.\n" | 193 | (define ifaces |
| 124 | port) | 194 | (filter valid? (all-network-interface-names))) |
| 125 | (for-each (lambda (server) | 195 | |
| 126 | (format port "nameserver ~a~%" | 196 | ;; XXX: Make sure the interfaces are up so that 'dhclient' can |
| 127 | server)) | 197 | ;; actually send/receive over them. |
| 128 | '#$name-servers))) | 198 | (for-each set-network-interface-up ifaces) |
| 129 | #t))) | 199 | |
| 130 | (stop #~(lambda _ | 200 | (false-if-exception (delete-file #$pid-file)) |
| 131 | ;; Return #f is successfully stopped. | 201 | (let ((pid (fork+exec-command |
| 132 | (let ((sock (socket AF_INET SOCK_STREAM 0))) | 202 | (cons* #$dhclient "-nw" |
| 133 | (set-network-interface-flags sock #$interface 0) | 203 | "-pf" #$pid-file ifaces)))) |
| 134 | (close-port sock)) | 204 | (and (zero? (cdr (waitpid pid))) |
| 135 | (not #$(if gateway | 205 | (let loop () |
| 136 | #~(system* (string-append #$net-tools | 206 | (catch 'system-error |
| 137 | "/sbin/route") | 207 | (lambda () |
| 138 | "del" "-net" "default") | 208 | (call-with-input-file #$pid-file read)) |
| 139 | #t)))) | 209 | (lambda args |
| 140 | (respawn? #f))) | 210 | ;; 'dhclient' returned before PID-FILE was created, |
| 211 | ;; so try again. | ||
| 212 | (let ((errno (system-error-errno args))) | ||
| 213 | (if (= ENOENT errno) | ||
| 214 | (begin | ||
| 215 | (sleep 1) | ||
| 216 | (loop)) | ||
| 217 | (apply throw args)))))))))) | ||
| 218 | (stop #~(make-kill-destructor)))))) | ||
| 141 | 219 | ||
| 142 | (define* (dhcp-client-service #:key (dhcp isc-dhcp)) | 220 | (define* (dhcp-client-service #:key (dhcp isc-dhcp)) |
| 143 | "Return a service that runs @var{dhcp}, a Dynamic Host Configuration | 221 | "Return a service that runs @var{dhcp}, a Dynamic Host Configuration |
| 144 | Protocol (DHCP) client, on all the non-loopback network interfaces." | 222 | Protocol (DHCP) client, on all the non-loopback network interfaces." |
| 145 | 223 | (service dhcp-client-service-type dhcp)) | |
| 146 | (define dhclient | ||
| 147 | #~(string-append #$dhcp "/sbin/dhclient")) | ||
| 148 | |||
| 149 | (define pid-file | ||
| 150 | "/var/run/dhclient.pid") | ||
| 151 | |||
| 152 | (service | ||
| 153 | (documentation "Set up networking via DHCP.") | ||
| 154 | (requirement '(user-processes udev)) | ||
| 155 | |||
| 156 | ;; XXX: Running with '-nw' ("no wait") avoids blocking for a minute when | ||
| 157 | ;; networking is unavailable, but also means that the interface is not up | ||
| 158 | ;; yet when 'start' completes. To wait for the interface to be ready, one | ||
| 159 | ;; should instead monitor udev events. | ||
| 160 | (provision '(networking)) | ||
| 161 | |||
| 162 | (start #~(lambda _ | ||
| 163 | ;; When invoked without any arguments, 'dhclient' discovers all | ||
| 164 | ;; non-loopback interfaces *that are up*. However, the relevant | ||
| 165 | ;; interfaces are typically down at this point. Thus we perform | ||
| 166 | ;; our own interface discovery here. | ||
| 167 | (define valid? | ||
| 168 | (negate loopback-network-interface?)) | ||
| 169 | (define ifaces | ||
| 170 | (filter valid? (all-network-interface-names))) | ||
| 171 | |||
| 172 | ;; XXX: Make sure the interfaces are up so that 'dhclient' can | ||
| 173 | ;; actually send/receive over them. | ||
| 174 | (for-each set-network-interface-up ifaces) | ||
| 175 | |||
| 176 | (false-if-exception (delete-file #$pid-file)) | ||
| 177 | (let ((pid (fork+exec-command | ||
| 178 | (cons* #$dhclient "-nw" | ||
| 179 | "-pf" #$pid-file ifaces)))) | ||
| 180 | (and (zero? (cdr (waitpid pid))) | ||
| 181 | (let loop () | ||
| 182 | (catch 'system-error | ||
| 183 | (lambda () | ||
| 184 | (call-with-input-file #$pid-file read)) | ||
| 185 | (lambda args | ||
| 186 | ;; 'dhclient' returned before PID-FILE was created, | ||
| 187 | ;; so try again. | ||
| 188 | (let ((errno (system-error-errno args))) | ||
| 189 | (if (= ENOENT errno) | ||
| 190 | (begin | ||
| 191 | (sleep 1) | ||
| 192 | (loop)) | ||
| 193 | (apply throw args)))))))))) | ||
| 194 | (stop #~(make-kill-destructor)))) | ||
| 195 | 224 | ||
| 196 | (define %ntp-servers | 225 | (define %ntp-servers |
| 197 | ;; Default set of NTP servers. | 226 | ;; Default set of NTP servers. |
| @@ -199,19 +228,30 @@ Protocol (DHCP) client, on all the non-loopback network interfaces." | |||
| 199 | "1.pool.ntp.org" | 228 | "1.pool.ntp.org" |
| 200 | "2.pool.ntp.org")) | 229 | "2.pool.ntp.org")) |
| 201 | 230 | ||
| 202 | (define* (ntp-service #:key (ntp ntp) | 231 | |
| 203 | (servers %ntp-servers)) | 232 | ;;; |
| 204 | "Return a service that runs the daemon from @var{ntp}, the | 233 | ;;; NTP. |
| 205 | @uref{http://www.ntp.org, Network Time Protocol package}. The daemon will | 234 | ;;; |
| 206 | keep the system clock synchronized with that of @var{servers}." | 235 | |
| 207 | ;; TODO: Add authentication support. | 236 | ;; TODO: Export. |
| 208 | 237 | (define-record-type* <ntp-configuration> | |
| 209 | (define config | 238 | ntp-configuration make-ntp-configuration |
| 210 | (string-append "driftfile /var/run/ntp.drift\n" | 239 | ntp-configuration? |
| 211 | (string-join (map (cut string-append "server " <>) | 240 | (ntp ntp-configuration-ntp |
| 212 | servers) | 241 | (default ntp)) |
| 213 | "\n") | 242 | (servers ntp-configuration-servers)) |
| 214 | " | 243 | |
| 244 | (define ntp-dmd-service | ||
| 245 | (match-lambda | ||
| 246 | (($ <ntp-configuration> ntp servers) | ||
| 247 | (let () | ||
| 248 | ;; TODO: Add authentication support. | ||
| 249 | (define config | ||
| 250 | (string-append "driftfile /var/run/ntp.drift\n" | ||
| 251 | (string-join (map (cut string-append "server " <>) | ||
| 252 | servers) | ||
| 253 | "\n") | ||
| 254 | " | ||
| 215 | # Disable status queries as a workaround for CVE-2013-5211: | 255 | # Disable status queries as a workaround for CVE-2013-5211: |
| 216 | # <http://support.ntp.org/bin/view/Main/SecurityNotice#DRDoS_Amplification_Attack_using>. | 256 | # <http://support.ntp.org/bin/view/Main/SecurityNotice#DRDoS_Amplification_Attack_using>. |
| 217 | restrict default kod nomodify notrap nopeer noquery | 257 | restrict default kod nomodify notrap nopeer noquery |
| @@ -221,55 +261,154 @@ restrict -6 default kod nomodify notrap nopeer noquery | |||
| 221 | restrict 127.0.0.1 | 261 | restrict 127.0.0.1 |
| 222 | restrict -6 ::1\n")) | 262 | restrict -6 ::1\n")) |
| 223 | 263 | ||
| 224 | (let ((ntpd.conf (plain-file "ntpd.conf" config))) | 264 | (define ntpd.conf |
| 225 | (service | 265 | (plain-file "ntpd.conf" config)) |
| 226 | (provision '(ntpd)) | 266 | |
| 227 | (documentation "Run the Network Time Protocol (NTP) daemon.") | 267 | (list (dmd-service |
| 228 | (requirement '(user-processes networking)) | 268 | (provision '(ntpd)) |
| 229 | (start #~(make-forkexec-constructor | 269 | (documentation "Run the Network Time Protocol (NTP) daemon.") |
| 230 | (list (string-append #$ntp "/bin/ntpd") "-n" | 270 | (requirement '(user-processes networking)) |
| 231 | "-c" #$ntpd.conf | 271 | (start #~(make-forkexec-constructor |
| 232 | "-u" "ntpd"))) | 272 | (list (string-append #$ntp "/bin/ntpd") "-n" |
| 233 | (stop #~(make-kill-destructor)) | 273 | "-c" #$ntpd.conf "-u" "ntpd"))) |
| 234 | (user-accounts (list (user-account | 274 | (stop #~(make-kill-destructor)))))))) |
| 235 | (name "ntpd") | 275 | |
| 236 | (group "nogroup") | 276 | (define %ntp-accounts |
| 237 | (system? #t) | 277 | (list (user-account |
| 238 | (comment "NTP daemon user") | 278 | (name "ntpd") |
| 239 | (home-directory "/var/empty") | 279 | (group "nogroup") |
| 240 | (shell | 280 | (system? #t) |
| 241 | #~(string-append #$shadow "/sbin/nologin")))))))) | 281 | (comment "NTP daemon user") |
| 282 | (home-directory "/var/empty") | ||
| 283 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 284 | |||
| 285 | (define ntp-service-type | ||
| 286 | (service-type (name 'ntp) | ||
| 287 | (extensions | ||
| 288 | (list (service-extension dmd-root-service-type | ||
| 289 | ntp-dmd-service) | ||
| 290 | (service-extension account-service-type | ||
| 291 | (const %ntp-accounts)))))) | ||
| 292 | |||
| 293 | (define* (ntp-service #:key (ntp ntp) | ||
| 294 | (servers %ntp-servers)) | ||
| 295 | "Return a service that runs the daemon from @var{ntp}, the | ||
| 296 | @uref{http://www.ntp.org, Network Time Protocol package}. The daemon will | ||
| 297 | keep the system clock synchronized with that of @var{servers}." | ||
| 298 | (service ntp-service-type | ||
| 299 | (ntp-configuration (ntp ntp) (servers servers)))) | ||
| 300 | |||
| 301 | |||
| 302 | ;;; | ||
| 303 | ;;; Tor. | ||
| 304 | ;;; | ||
| 305 | |||
| 306 | (define %tor-accounts | ||
| 307 | ;; User account and groups for Tor. | ||
| 308 | (list (user-group (name "tor") (system? #t)) | ||
| 309 | (user-account | ||
| 310 | (name "tor") | ||
| 311 | (group "tor") | ||
| 312 | (system? #t) | ||
| 313 | (comment "Tor daemon user") | ||
| 314 | (home-directory "/var/empty") | ||
| 315 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 316 | |||
| 317 | (define (tor-dmd-service tor) | ||
| 318 | "Return a <dmd-service> running TOR." | ||
| 319 | (let ((torrc (plain-file "torrc" "User tor\n"))) | ||
| 320 | (list (dmd-service | ||
| 321 | (provision '(tor)) | ||
| 322 | |||
| 323 | ;; Tor needs at least one network interface to be up, hence the | ||
| 324 | ;; dependency on 'loopback'. | ||
| 325 | (requirement '(user-processes loopback)) | ||
| 326 | |||
| 327 | (start #~(make-forkexec-constructor | ||
| 328 | (list (string-append #$tor "/bin/tor") "-f" #$torrc))) | ||
| 329 | (stop #~(make-kill-destructor)) | ||
| 330 | (documentation "Run the Tor anonymous network overlay."))))) | ||
| 331 | |||
| 332 | (define tor-service-type | ||
| 333 | (service-type (name 'tor) | ||
| 334 | (extensions | ||
| 335 | (list (service-extension dmd-root-service-type | ||
| 336 | tor-dmd-service) | ||
| 337 | (service-extension account-service-type | ||
| 338 | (const %tor-accounts)))))) | ||
| 242 | 339 | ||
| 243 | (define* (tor-service #:key (tor tor)) | 340 | (define* (tor-service #:key (tor tor)) |
| 244 | "Return a service to run the @uref{https://torproject.org,Tor} daemon. | 341 | "Return a service to run the @uref{https://torproject.org,Tor} daemon. |
| 245 | 342 | ||
| 246 | The daemon runs with the default settings (in particular the default exit | 343 | The daemon runs with the default settings (in particular the default exit |
| 247 | policy) as the @code{tor} unprivileged user." | 344 | policy) as the @code{tor} unprivileged user." |
| 248 | (let ((torrc (plain-file "torrc" "User tor\n"))) | 345 | (service tor-service-type tor)) |
| 249 | (service | 346 | |
| 250 | (provision '(tor)) | 347 | |
| 251 | 348 | ;;; | |
| 252 | ;; Tor needs at least one network interface to be up, hence the | 349 | ;;; BitlBee. |
| 253 | ;; dependency on 'loopback'. | 350 | ;;; |
| 254 | (requirement '(user-processes loopback)) | 351 | |
| 255 | 352 | (define-record-type* <bitlbee-configuration> | |
| 256 | (start #~(make-forkexec-constructor | 353 | bitlbee-configuration make-bitlbee-configuration |
| 257 | (list (string-append #$tor "/bin/tor") "-f" #$torrc))) | 354 | bitlbee-configuration? |
| 258 | (stop #~(make-kill-destructor)) | 355 | (bitlbee bitlbee-configuration-bitlbee |
| 259 | 356 | (default bitlbee)) | |
| 260 | (user-groups (list (user-group | 357 | (interface bitlbee-configuration-interface) |
| 261 | (name "tor") | 358 | (port bitlbee-configuration-port) |
| 262 | (system? #t)))) | 359 | (extra-settings bitlbee-configuration-extra-settings)) |
| 263 | (user-accounts (list (user-account | 360 | |
| 264 | (name "tor") | 361 | (define bitlbee-dmd-service |
| 265 | (group "tor") | 362 | (match-lambda |
| 266 | (system? #t) | 363 | (($ <bitlbee-configuration> bitlbee interface port extra-settings) |
| 267 | (comment "Tor daemon user") | 364 | (let ((conf (plain-file "bitlbee.conf" |
| 268 | (home-directory "/var/empty") | 365 | (string-append " |
| 269 | (shell | 366 | [settings] |
| 270 | #~(string-append #$shadow "/sbin/nologin"))))) | 367 | User = bitlbee |
| 271 | 368 | ConfigDir = /var/lib/bitlbee | |
| 272 | (documentation "Run the Tor anonymous network overlay.")))) | 369 | DaemonInterface = " interface " |
| 370 | DaemonPort = " (number->string port) " | ||
| 371 | " extra-settings)))) | ||
| 372 | |||
| 373 | (list (dmd-service | ||
| 374 | (provision '(bitlbee)) | ||
| 375 | (requirement '(user-processes loopback)) | ||
| 376 | (start #~(make-forkexec-constructor | ||
| 377 | (list (string-append #$bitlbee "/sbin/bitlbee") | ||
| 378 | "-n" "-F" "-u" "bitlbee" "-c" #$conf))) | ||
| 379 | (stop #~(make-kill-destructor)))))))) | ||
| 380 | |||
| 381 | (define %bitlbee-accounts | ||
| 382 | ;; User group and account to run BitlBee. | ||
| 383 | (list (user-group (name "bitlbee") (system? #t)) | ||
| 384 | (user-account | ||
| 385 | (name "bitlbee") | ||
| 386 | (group "bitlbee") | ||
| 387 | (system? #t) | ||
| 388 | (comment "BitlBee daemon user") | ||
| 389 | (home-directory "/var/empty") | ||
| 390 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 391 | |||
| 392 | (define %bitlbee-activation | ||
| 393 | ;; Activation gexp for BitlBee. | ||
| 394 | #~(begin | ||
| 395 | (use-modules (guix build utils)) | ||
| 396 | |||
| 397 | ;; This directory is used to store OTR data. | ||
| 398 | (mkdir-p "/var/lib/bitlbee") | ||
| 399 | (let ((user (getpwnam "bitlbee"))) | ||
| 400 | (chown "/var/lib/bitlbee" | ||
| 401 | (passwd:uid user) (passwd:gid user))))) | ||
| 402 | |||
| 403 | (define bitlbee-service-type | ||
| 404 | (service-type (name 'bitlbee) | ||
| 405 | (extensions | ||
| 406 | (list (service-extension dmd-root-service-type | ||
| 407 | bitlbee-dmd-service) | ||
| 408 | (service-extension account-service-type | ||
| 409 | (const %bitlbee-accounts)) | ||
| 410 | (service-extension activation-service-type | ||
| 411 | (const %bitlbee-activation)))))) | ||
| 273 | 412 | ||
| 274 | (define* (bitlbee-service #:key (bitlbee bitlbee) | 413 | (define* (bitlbee-service #:key (bitlbee bitlbee) |
| 275 | (interface "127.0.0.1") (port 6667) | 414 | (interface "127.0.0.1") (port 6667) |
| @@ -284,57 +423,52 @@ come from any networking interface. | |||
| 284 | 423 | ||
| 285 | In addition, @var{extra-settings} specifies a string to append to the | 424 | In addition, @var{extra-settings} specifies a string to append to the |
| 286 | configuration file." | 425 | configuration file." |
| 287 | (let ((conf (plain-file "bitlbee.conf" | 426 | (service bitlbee-service-type |
| 288 | (string-append " | 427 | (bitlbee-configuration |
| 289 | [settings] | 428 | (bitlbee bitlbee) |
| 290 | User = bitlbee | 429 | (interface interface) (port port) |
| 291 | ConfigDir = /var/lib/bitlbee | 430 | (extra-settings extra-settings)))) |
| 292 | DaemonInterface = " interface " | 431 | |
| 293 | DaemonPort = " (number->string port) " | 432 | |
| 294 | " extra-settings)))) | 433 | ;;; |
| 295 | (service | 434 | ;;; Wicd. |
| 296 | (provision '(bitlbee)) | 435 | ;;; |
| 297 | (requirement '(user-processes loopback)) | 436 | |
| 298 | (activate #~(begin | 437 | (define %wicd-activation |
| 299 | (use-modules (guix build utils)) | 438 | ;; Activation gexp for Wicd. |
| 300 | 439 | #~(begin | |
| 301 | ;; This directory is used to store OTR data. | 440 | (use-modules (guix build utils)) |
| 302 | (mkdir-p "/var/lib/bitlbee") | 441 | |
| 303 | (let ((user (getpwnam "bitlbee"))) | 442 | (mkdir-p "/etc/wicd") |
| 304 | (chown "/var/lib/bitlbee" | 443 | (let ((file-name "/etc/wicd/dhclient.conf.template.default")) |
| 305 | (passwd:uid user) (passwd:gid user))))) | 444 | (unless (file-exists? file-name) |
| 306 | (start #~(make-forkexec-constructor | 445 | (copy-file (string-append #$wicd file-name) |
| 307 | (list (string-append #$bitlbee "/sbin/bitlbee") | 446 | file-name))))) |
| 308 | "-n" "-F" "-u" "bitlbee" "-c" #$conf))) | 447 | |
| 309 | (stop #~(make-kill-destructor)) | 448 | (define (wicd-dmd-service wicd) |
| 310 | (user-groups (list (user-group (name "bitlbee") (system? #t)))) | 449 | "Return a dmd service for WICD." |
| 311 | (user-accounts (list (user-account | 450 | (list (dmd-service |
| 312 | (name "bitlbee") | 451 | (documentation "Run the Wicd network manager.") |
| 313 | (group "bitlbee") | 452 | (provision '(networking)) |
| 314 | (system? #t) | 453 | (requirement '(user-processes dbus-system loopback)) |
| 315 | (comment "BitlBee daemon user") | 454 | (start #~(make-forkexec-constructor |
| 316 | (home-directory "/var/empty") | 455 | (list (string-append #$wicd "/sbin/wicd") |
| 317 | (shell #~(string-append #$shadow | 456 | "--no-daemon"))) |
| 318 | "/sbin/nologin")))))))) | 457 | (stop #~(make-kill-destructor))))) |
| 458 | |||
| 459 | (define wicd-service-type | ||
| 460 | (service-type (name 'wicd) | ||
| 461 | (extensions | ||
| 462 | (list (service-extension dmd-root-service-type | ||
| 463 | wicd-dmd-service) | ||
| 464 | (service-extension dbus-root-service-type | ||
| 465 | list) | ||
| 466 | (service-extension activation-service-type | ||
| 467 | (const %wicd-activation)))))) | ||
| 319 | 468 | ||
| 320 | (define* (wicd-service #:key (wicd wicd)) | 469 | (define* (wicd-service #:key (wicd wicd)) |
| 321 | "Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network | 470 | "Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network |
| 322 | manager that aims to simplify wired and wireless networking." | 471 | manager that aims to simplify wired and wireless networking." |
| 323 | (service | 472 | (service wicd-service-type wicd)) |
| 324 | (documentation "Run the Wicd network manager.") | ||
| 325 | (provision '(networking)) | ||
| 326 | (requirement '(user-processes dbus-system loopback)) | ||
| 327 | (start #~(make-forkexec-constructor | ||
| 328 | (list (string-append #$wicd "/sbin/wicd") | ||
| 329 | "--no-daemon"))) | ||
| 330 | (stop #~(make-kill-destructor)) | ||
| 331 | (activate | ||
| 332 | #~(begin | ||
| 333 | (use-modules (guix build utils)) | ||
| 334 | (mkdir-p "/etc/wicd") | ||
| 335 | (let ((file-name "/etc/wicd/dhclient.conf.template.default")) | ||
| 336 | (unless (file-exists? file-name) | ||
| 337 | (copy-file (string-append #$wicd file-name) | ||
| 338 | file-name))))))) | ||
| 339 | 473 | ||
| 340 | ;;; networking.scm ends here | 474 | ;;; networking.scm ends here |
diff --git a/gnu/services/ssh.scm b/gnu/services/ssh.scm index 3fa0976054d..d3a6cfb33ac 100644 --- a/gnu/services/ssh.scm +++ b/gnu/services/ssh.scm | |||
| @@ -18,8 +18,9 @@ | |||
| 18 | 18 | ||
| 19 | (define-module (gnu services ssh) | 19 | (define-module (gnu services ssh) |
| 20 | #:use-module (guix gexp) | 20 | #:use-module (guix gexp) |
| 21 | #:use-module (guix store) | 21 | #:use-module (guix records) |
| 22 | #:use-module (gnu services) | 22 | #:use-module (gnu services) |
| 23 | #:use-module (gnu services dmd) | ||
| 23 | #:use-module (gnu system linux) ; 'pam-service' | 24 | #:use-module (gnu system linux) ; 'pam-service' |
| 24 | #:use-module (gnu packages lsh) | 25 | #:use-module (gnu packages lsh) |
| 25 | #:export (lsh-service)) | 26 | #:export (lsh-service)) |
| @@ -30,11 +31,32 @@ | |||
| 30 | ;;; | 31 | ;;; |
| 31 | ;;; Code: | 32 | ;;; Code: |
| 32 | 33 | ||
| 34 | ;; TODO: Export. | ||
| 35 | (define-record-type* <lsh-configuration> | ||
| 36 | lsh-configuration make-lsh-configuration | ||
| 37 | lsh-configuration? | ||
| 38 | (lsh lsh-configuration-lsh | ||
| 39 | (default lsh)) | ||
| 40 | (daemonic? lsh-configuration-daemonic?) | ||
| 41 | (host-key lsh-configuration-host-key) | ||
| 42 | (interfaces lsh-configuration-interfaces) | ||
| 43 | (port-number lsh-configuration-port-number) | ||
| 44 | (allow-empty-passwords? lsh-configuration-allow-empty-passwords?) | ||
| 45 | (root-login? lsh-configuration-root-login?) | ||
| 46 | (syslog-output? lsh-configuration-syslog-output?) | ||
| 47 | (pid-file? lsh-configuration-pid-file?) | ||
| 48 | (pid-file lsh-configuration-pid-file) | ||
| 49 | (x11-forwarding? lsh-configuration-x11-forwarding?) | ||
| 50 | (tcp/ip-forwarding? lsh-configuration-tcp/ip-forwarding?) | ||
| 51 | (password-authentication? lsh-configuration-password-authentication?) | ||
| 52 | (public-key-authentication? lsh-configuration-public-key-authentication?) | ||
| 53 | (initialize? lsh-configuration-initialize?)) | ||
| 54 | |||
| 33 | (define %yarrow-seed | 55 | (define %yarrow-seed |
| 34 | "/var/spool/lsh/yarrow-seed-file") | 56 | "/var/spool/lsh/yarrow-seed-file") |
| 35 | 57 | ||
| 36 | (define (activation lsh host-key) | 58 | (define (lsh-initialization lsh host-key) |
| 37 | "Return the gexp to activate the LSH service for HOST-KEY." | 59 | "Return the gexp to initialize the LSH service for HOST-KEY." |
| 38 | #~(begin | 60 | #~(begin |
| 39 | (unless (file-exists? #$%yarrow-seed) | 61 | (unless (file-exists? #$%yarrow-seed) |
| 40 | (system* (string-append #$lsh "/bin/lsh-make-seed") | 62 | (system* (string-append #$lsh "/bin/lsh-make-seed") |
| @@ -70,6 +92,88 @@ | |||
| 70 | (waitpid keygen) | 92 | (waitpid keygen) |
| 71 | (waitpid write-key)))))))))) | 93 | (waitpid write-key)))))))))) |
| 72 | 94 | ||
| 95 | (define (lsh-activation config) | ||
| 96 | "Return the activation gexp for CONFIG." | ||
| 97 | #~(begin | ||
| 98 | (use-modules (guix build utils)) | ||
| 99 | (mkdir-p "/var/spool/lsh") | ||
| 100 | #$(if (lsh-configuration-initialize? config) | ||
| 101 | (lsh-initialization (lsh-configuration-lsh config) | ||
| 102 | (lsh-configuration-host-key config)) | ||
| 103 | #t))) | ||
| 104 | |||
| 105 | (define (lsh-dmd-service config) | ||
| 106 | "Return a <dmd-service> for lsh with CONFIG." | ||
| 107 | (define lsh (lsh-configuration-lsh config)) | ||
| 108 | (define pid-file (lsh-configuration-pid-file config)) | ||
| 109 | (define pid-file? (lsh-configuration-pid-file? config)) | ||
| 110 | (define daemonic? (lsh-configuration-daemonic? config)) | ||
| 111 | (define interfaces (lsh-configuration-interfaces config)) | ||
| 112 | |||
| 113 | (define lsh-command | ||
| 114 | (append | ||
| 115 | (cons #~(string-append #$lsh "/sbin/lshd") | ||
| 116 | (if daemonic? | ||
| 117 | (let ((syslog (if (lsh-configuration-syslog-output? config) | ||
| 118 | '() | ||
| 119 | (list "--no-syslog")))) | ||
| 120 | (cons "--daemonic" | ||
| 121 | (if pid-file? | ||
| 122 | (cons #~(string-append "--pid-file=" #$pid-file) | ||
| 123 | syslog) | ||
| 124 | (cons "--no-pid-file" syslog)))) | ||
| 125 | (if pid-file? | ||
| 126 | (list #~(string-append "--pid-file=" #$pid-file)) | ||
| 127 | '()))) | ||
| 128 | (cons* #~(string-append "--host-key=" | ||
| 129 | #$(lsh-configuration-host-key config)) | ||
| 130 | #~(string-append "--password-helper=" #$lsh "/sbin/lsh-pam-checkpw") | ||
| 131 | #~(string-append "--subsystems=sftp=" #$lsh "/sbin/sftp-server") | ||
| 132 | "-p" (number->string (lsh-configuration-port-number config)) | ||
| 133 | (if (lsh-configuration-password-authentication? config) | ||
| 134 | "--password" "--no-password") | ||
| 135 | (if (lsh-configuration-public-key-authentication? config) | ||
| 136 | "--publickey" "--no-publickey") | ||
| 137 | (if (lsh-configuration-root-login? config) | ||
| 138 | "--root-login" "--no-root-login") | ||
| 139 | (if (lsh-configuration-x11-forwarding? config) | ||
| 140 | "--x11-forward" "--no-x11-forward") | ||
| 141 | (if (lsh-configuration-tcp/ip-forwarding? config) | ||
| 142 | "--tcpip-forward" "--no-tcpip-forward") | ||
| 143 | (if (null? interfaces) | ||
| 144 | '() | ||
| 145 | (list (string-append "--interfaces=" | ||
| 146 | (string-join interfaces ","))))))) | ||
| 147 | |||
| 148 | (define requires | ||
| 149 | (if (and daemonic? (lsh-configuration-syslog-output? config)) | ||
| 150 | '(networking syslogd) | ||
| 151 | '(networking))) | ||
| 152 | |||
| 153 | (list (dmd-service | ||
| 154 | (documentation "GNU lsh SSH server") | ||
| 155 | (provision '(ssh-daemon)) | ||
| 156 | (requirement requires) | ||
| 157 | (start #~(make-forkexec-constructor (list #$@lsh-command))) | ||
| 158 | (stop #~(make-kill-destructor))))) | ||
| 159 | |||
| 160 | (define (lsh-pam-services config) | ||
| 161 | "Return a list of <pam-services> for lshd with CONFIG." | ||
| 162 | (list (unix-pam-service | ||
| 163 | "lshd" | ||
| 164 | #:allow-empty-passwords? | ||
| 165 | (lsh-configuration-allow-empty-passwords? config)))) | ||
| 166 | |||
| 167 | (define lsh-service-type | ||
| 168 | (service-type (name 'lsh) | ||
| 169 | (extensions | ||
| 170 | (list (service-extension dmd-root-service-type | ||
| 171 | lsh-dmd-service) | ||
| 172 | (service-extension pam-root-service-type | ||
| 173 | lsh-pam-services) | ||
| 174 | (service-extension activation-service-type | ||
| 175 | lsh-activation))))) | ||
| 176 | |||
| 73 | (define* (lsh-service #:key | 177 | (define* (lsh-service #:key |
| 74 | (lsh lsh) | 178 | (lsh lsh) |
| 75 | (daemonic? #t) | 179 | (daemonic? #t) |
| @@ -114,58 +218,20 @@ passwords, and @var{root-login?} specifies whether to accept log-ins as | |||
| 114 | root. | 218 | root. |
| 115 | 219 | ||
| 116 | The other options should be self-descriptive." | 220 | The other options should be self-descriptive." |
| 117 | (define lsh-command | 221 | (service lsh-service-type |
| 118 | (append | 222 | (lsh-configuration (lsh lsh) (daemonic? daemonic?) |
| 119 | (cons #~(string-append #$lsh "/sbin/lshd") | 223 | (host-key host-key) (interfaces interfaces) |
| 120 | (if daemonic? | 224 | (port-number port-number) |
| 121 | (let ((syslog (if syslog-output? '() | 225 | (allow-empty-passwords? allow-empty-passwords?) |
| 122 | (list "--no-syslog")))) | 226 | (root-login? root-login?) |
| 123 | (cons "--daemonic" | 227 | (syslog-output? syslog-output?) |
| 124 | (if pid-file? | 228 | (pid-file? pid-file?) (pid-file pid-file) |
| 125 | (cons #~(string-append "--pid-file=" #$pid-file) | 229 | (x11-forwarding? x11-forwarding?) |
| 126 | syslog) | 230 | (tcp/ip-forwarding? tcp/ip-forwarding?) |
| 127 | (cons "--no-pid-file" syslog)))) | 231 | (password-authentication? |
| 128 | (if pid-file? | 232 | password-authentication?) |
| 129 | (list #~(string-append "--pid-file=" #$pid-file)) | 233 | (public-key-authentication? |
| 130 | '()))) | 234 | public-key-authentication?) |
| 131 | (cons* #~(string-append "--host-key=" #$host-key) | 235 | (initialize? initialize?)))) |
| 132 | #~(string-append "--password-helper=" #$lsh "/sbin/lsh-pam-checkpw") | ||
| 133 | #~(string-append "--subsystems=sftp=" #$lsh "/sbin/sftp-server") | ||
| 134 | "-p" (number->string port-number) | ||
| 135 | (if password-authentication? "--password" "--no-password") | ||
| 136 | (if public-key-authentication? | ||
| 137 | "--publickey" "--no-publickey") | ||
| 138 | (if root-login? | ||
| 139 | "--root-login" "--no-root-login") | ||
| 140 | (if x11-forwarding? | ||
| 141 | "--x11-forward" "--no-x11-forward") | ||
| 142 | (if tcp/ip-forwarding? | ||
| 143 | "--tcpip-forward" "--no-tcpip-forward") | ||
| 144 | (if (null? interfaces) | ||
| 145 | '() | ||
| 146 | (list (string-append "--interfaces=" | ||
| 147 | (string-join interfaces ","))))))) | ||
| 148 | |||
| 149 | (define requires | ||
| 150 | (if (and daemonic? syslog-output?) | ||
| 151 | '(networking syslogd) | ||
| 152 | '(networking))) | ||
| 153 | |||
| 154 | (service | ||
| 155 | (documentation "GNU lsh SSH server") | ||
| 156 | (provision '(ssh-daemon)) | ||
| 157 | (requirement requires) | ||
| 158 | (start #~(make-forkexec-constructor (list #$@lsh-command))) | ||
| 159 | (stop #~(make-kill-destructor)) | ||
| 160 | (pam-services | ||
| 161 | (list (unix-pam-service | ||
| 162 | "lshd" | ||
| 163 | #:allow-empty-passwords? allow-empty-passwords?))) | ||
| 164 | (activate #~(begin | ||
| 165 | (use-modules (guix build utils)) | ||
| 166 | (mkdir-p "/var/spool/lsh") | ||
| 167 | #$(if initialize? | ||
| 168 | (activation lsh host-key) | ||
| 169 | #t))))) | ||
| 170 | 236 | ||
| 171 | ;;; ssh.scm ends here | 237 | ;;; ssh.scm ends here |
diff --git a/gnu/services/web.scm b/gnu/services/web.scm index c6b4153d05a..84bb30d8fd0 100644 --- a/gnu/services/web.scm +++ b/gnu/services/web.scm | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> | 2 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> |
| 3 | ;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | ;;; | 4 | ;;; |
| 4 | ;;; This file is part of GNU Guix. | 5 | ;;; This file is part of GNU Guix. |
| 5 | ;;; | 6 | ;;; |
| @@ -18,12 +19,13 @@ | |||
| 18 | 19 | ||
| 19 | (define-module (gnu services web) | 20 | (define-module (gnu services web) |
| 20 | #:use-module (gnu services) | 21 | #:use-module (gnu services) |
| 22 | #:use-module (gnu services dmd) | ||
| 21 | #:use-module (gnu system shadow) | 23 | #:use-module (gnu system shadow) |
| 22 | #:use-module (gnu packages admin) | 24 | #:use-module (gnu packages admin) |
| 23 | #:use-module (gnu packages web) | 25 | #:use-module (gnu packages web) |
| 24 | #:use-module (guix records) | 26 | #:use-module (guix records) |
| 25 | #:use-module (guix store) | ||
| 26 | #:use-module (guix gexp) | 27 | #:use-module (guix gexp) |
| 28 | #:use-module (ice-9 match) | ||
| 27 | #:export (nginx-service)) | 29 | #:export (nginx-service)) |
| 28 | 30 | ||
| 29 | ;;; Commentary: | 31 | ;;; Commentary: |
| @@ -32,6 +34,14 @@ | |||
| 32 | ;;; | 34 | ;;; |
| 33 | ;;; Code: | 35 | ;;; Code: |
| 34 | 36 | ||
| 37 | (define-record-type* <nginx-configuration> | ||
| 38 | nginx-configuration make-nginx-configuration | ||
| 39 | nginx-configuration? | ||
| 40 | (nginx nginx-configuration-nginx) ;<package> | ||
| 41 | (log-directory nginx-configuration-log-directory) ;string | ||
| 42 | (run-directory nginx-configuration-run-directory) ;string | ||
| 43 | (file nginx-configuration-file)) ;string | file-like | ||
| 44 | |||
| 35 | (define (default-nginx-config log-directory run-directory) | 45 | (define (default-nginx-config log-directory run-directory) |
| 36 | (plain-file "nginx.conf" | 46 | (plain-file "nginx.conf" |
| 37 | (string-append | 47 | (string-append |
| @@ -45,6 +55,58 @@ | |||
| 45 | "}\n" | 55 | "}\n" |
| 46 | "events {}\n"))) | 56 | "events {}\n"))) |
| 47 | 57 | ||
| 58 | (define %nginx-accounts | ||
| 59 | (list (user-group (name "nginx") (system? #t)) | ||
| 60 | (user-account | ||
| 61 | (name "nginx") | ||
| 62 | (group "nginx") | ||
| 63 | (system? #t) | ||
| 64 | (comment "nginx server user") | ||
| 65 | (home-directory "/var/empty") | ||
| 66 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | ||
| 67 | |||
| 68 | (define nginx-activation | ||
| 69 | (match-lambda | ||
| 70 | (($ <nginx-configuration> nginx log-directory run-directory config-file) | ||
| 71 | #~(begin | ||
| 72 | (use-modules (guix build utils)) | ||
| 73 | |||
| 74 | (format #t "creating nginx log directory '~a'~%" #$log-directory) | ||
| 75 | (mkdir-p #$log-directory) | ||
| 76 | (format #t "creating nginx run directory '~a'~%" #$run-directory) | ||
| 77 | (mkdir-p #$run-directory) | ||
| 78 | ;; Check configuration file syntax. | ||
| 79 | (system* (string-append #$nginx "/bin/nginx") | ||
| 80 | "-c" #$config-file "-t"))))) | ||
| 81 | |||
| 82 | (define nginx-dmd-service | ||
| 83 | (match-lambda | ||
| 84 | (($ <nginx-configuration> nginx log-directory run-directory config-file) | ||
| 85 | (let* ((nginx-binary #~(string-append #$nginx "/sbin/nginx")) | ||
| 86 | (nginx-action | ||
| 87 | (lambda args | ||
| 88 | #~(lambda _ | ||
| 89 | (zero? | ||
| 90 | (system* #$nginx-binary "-c" #$config-file #$@args)))))) | ||
| 91 | |||
| 92 | ;; TODO: Add 'reload' action. | ||
| 93 | (list (dmd-service | ||
| 94 | (provision '(nginx)) | ||
| 95 | (documentation "Run the nginx daemon.") | ||
| 96 | (requirement '(user-processes loopback)) | ||
| 97 | (start (nginx-action "-p" run-directory)) | ||
| 98 | (stop (nginx-action "-s" "stop")))))))) | ||
| 99 | |||
| 100 | (define nginx-service-type | ||
| 101 | (service-type (name 'nginx) | ||
| 102 | (extensions | ||
| 103 | (list (service-extension dmd-root-service-type | ||
| 104 | nginx-dmd-service) | ||
| 105 | (service-extension activation-service-type | ||
| 106 | nginx-activation) | ||
| 107 | (service-extension account-service-type | ||
| 108 | (const %nginx-accounts)))))) | ||
| 109 | |||
| 48 | (define* (nginx-service #:key (nginx nginx) | 110 | (define* (nginx-service #:key (nginx nginx) |
| 49 | (log-directory "/var/log/nginx") | 111 | (log-directory "/var/log/nginx") |
| 50 | (run-directory "/var/run/nginx") | 112 | (run-directory "/var/run/nginx") |
| @@ -54,41 +116,9 @@ | |||
| 54 | 116 | ||
| 55 | The nginx daemon loads its runtime configuration from CONFIG-FIGLE, stores log | 117 | The nginx daemon loads its runtime configuration from CONFIG-FIGLE, stores log |
| 56 | files in LOG-DIRECTORY, and stores temporary runtime files in RUN-DIRECTORY." | 118 | files in LOG-DIRECTORY, and stores temporary runtime files in RUN-DIRECTORY." |
| 57 | (define nginx-binary | 119 | (service nginx-service-type |
| 58 | #~(string-append #$nginx "/sbin/nginx")) | 120 | (nginx-configuration |
| 59 | 121 | (nginx nginx) | |
| 60 | (define (nginx-action . args) | 122 | (log-directory log-directory) |
| 61 | #~(lambda _ | 123 | (run-directory run-directory) |
| 62 | (zero? | 124 | (file config-file)))) |
| 63 | (system* #$nginx-binary "-c" #$config-file #$@args)))) | ||
| 64 | |||
| 65 | (define activate | ||
| 66 | #~(begin | ||
| 67 | (use-modules (guix build utils)) | ||
| 68 | (format #t "creating nginx log directory '~a'~%" #$log-directory) | ||
| 69 | (mkdir-p #$log-directory) | ||
| 70 | (format #t "creating nginx run directory '~a'~%" #$run-directory) | ||
| 71 | (mkdir-p #$run-directory) | ||
| 72 | ;; Check configuration file syntax. | ||
| 73 | (system* #$nginx-binary "-c" #$config-file "-t"))) | ||
| 74 | |||
| 75 | (define nologin #~(string-append #$shadow "/sbin/nologin")) | ||
| 76 | |||
| 77 | ;; TODO: Add 'reload' action. | ||
| 78 | (service | ||
| 79 | (provision '(nginx)) | ||
| 80 | (documentation "Run the nginx daemon.") | ||
| 81 | (requirement '(user-processes loopback)) | ||
| 82 | (start (nginx-action "-p" run-directory)) | ||
| 83 | (stop (nginx-action "-s" "stop")) | ||
| 84 | (activate activate) | ||
| 85 | (user-groups (list (user-group | ||
| 86 | (name "nginx") | ||
| 87 | (system? #t)))) | ||
| 88 | (user-accounts (list (user-account | ||
| 89 | (name "nginx") | ||
| 90 | (group "nginx") | ||
| 91 | (system? #t) | ||
| 92 | (comment "nginx server user") | ||
| 93 | (home-directory "/var/empty") | ||
| 94 | (shell nologin)))))) | ||
diff --git a/gnu/services/xorg.scm b/gnu/services/xorg.scm index 9c96aab2b8d..812cb3f7254 100644 --- a/gnu/services/xorg.scm +++ b/gnu/services/xorg.scm | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | (define-module (gnu services xorg) | 20 | (define-module (gnu services xorg) |
| 21 | #:use-module (gnu artwork) | 21 | #:use-module (gnu artwork) |
| 22 | #:use-module (gnu services) | 22 | #:use-module (gnu services) |
| 23 | #:use-module (gnu services dmd) | ||
| 23 | #:use-module (gnu system linux) ; 'pam-service' | 24 | #:use-module (gnu system linux) ; 'pam-service' |
| 24 | #:use-module ((gnu packages base) #:select (canonical-package)) | 25 | #:use-module ((gnu packages base) #:select (canonical-package)) |
| 25 | #:use-module (gnu packages guile) | 26 | #:use-module (gnu packages guile) |
| @@ -212,6 +213,95 @@ which should be passed to this script as the first argument. If not, the | |||
| 212 | ;; contains the actual theme files. | 213 | ;; contains the actual theme files. |
| 213 | "0.x") | 214 | "0.x") |
| 214 | 215 | ||
| 216 | (define-record-type* <slim-configuration> | ||
| 217 | slim-configuration make-slim-configuration | ||
| 218 | slim-configuration? | ||
| 219 | (slim slim-configuration-slim | ||
| 220 | (default slim)) | ||
| 221 | (allow-empty-passwords? slim-configuration-allow-empty-passwords?) | ||
| 222 | (auto-login? slim-configuration-auto-login?) | ||
| 223 | (default-user slim-configuration-default-user) | ||
| 224 | (theme slim-configuration-theme) | ||
| 225 | (theme-name slim-configuration-theme-name) | ||
| 226 | (xauth slim-configuration-xauth | ||
| 227 | (default xauth)) | ||
| 228 | (dmd slim-configuration-dmd | ||
| 229 | (default dmd)) | ||
| 230 | (bash slim-configuration-bash | ||
| 231 | (default bash)) | ||
| 232 | (auto-login-session slim-configuration-auto-login-session) | ||
| 233 | (startx slim-configuration-startx)) | ||
| 234 | |||
| 235 | (define (slim-pam-service config) | ||
| 236 | "Return a PAM service for @command{slim}." | ||
| 237 | (list (unix-pam-service | ||
| 238 | "slim" | ||
| 239 | #:allow-empty-passwords? | ||
| 240 | (slim-configuration-allow-empty-passwords? config)))) | ||
| 241 | |||
| 242 | (define (slim-dmd-service config) | ||
| 243 | (define slim.cfg | ||
| 244 | (let ((xinitrc (xinitrc #:fallback-session | ||
| 245 | (slim-configuration-auto-login-session config))) | ||
| 246 | (slim (slim-configuration-slim config)) | ||
| 247 | (xauth (slim-configuration-xauth config)) | ||
| 248 | (startx (slim-configuration-startx config)) | ||
| 249 | (dmd (slim-configuration-dmd config)) | ||
| 250 | (theme-name (slim-configuration-theme-name config))) | ||
| 251 | (mixed-text-file "slim.cfg" " | ||
| 252 | default_path /run/current-system/profile/bin | ||
| 253 | default_xserver " startx " | ||
| 254 | xserver_arguments :0 vt7 | ||
| 255 | xauth_path " xauth "/bin/xauth | ||
| 256 | authfile /var/run/slim.auth | ||
| 257 | |||
| 258 | # The login command. '%session' is replaced by the chosen session name, one | ||
| 259 | # of the names specified in the 'sessions' setting: 'wmaker', 'xfce', etc. | ||
| 260 | login_cmd exec " xinitrc " %session | ||
| 261 | sessiondir /run/current-system/profile/share/xsessions | ||
| 262 | session_msg session (F1 to change): | ||
| 263 | |||
| 264 | halt_cmd " dmd "/sbin/halt | ||
| 265 | reboot_cmd " dmd "/sbin/reboot\n" | ||
| 266 | (if (slim-configuration-auto-login? config) | ||
| 267 | (string-append "auto_login yes\ndefault_user " | ||
| 268 | (slim-configuration-default-user config) "\n") | ||
| 269 | "") | ||
| 270 | (if theme-name | ||
| 271 | (string-append "current_theme " theme-name "\n") | ||
| 272 | "")))) | ||
| 273 | |||
| 274 | (define theme | ||
| 275 | (slim-configuration-theme config)) | ||
| 276 | |||
| 277 | (list (dmd-service | ||
| 278 | (documentation "Xorg display server") | ||
| 279 | (provision '(xorg-server)) | ||
| 280 | (requirement '(user-processes host-name udev)) | ||
| 281 | (start | ||
| 282 | #~(lambda () | ||
| 283 | ;; A stale lock file can prevent SLiM from starting, so remove it to | ||
| 284 | ;; be on the safe side. | ||
| 285 | (false-if-exception (delete-file "/var/run/slim.lock")) | ||
| 286 | |||
| 287 | (fork+exec-command | ||
| 288 | (list (string-append #$slim "/bin/slim") "-nodaemon") | ||
| 289 | #:environment-variables | ||
| 290 | (list (string-append "SLIM_CFGFILE=" #$slim.cfg) | ||
| 291 | #$@(if theme | ||
| 292 | (list #~(string-append "SLIM_THEMESDIR=" #$theme)) | ||
| 293 | #~()))))) | ||
| 294 | (stop #~(make-kill-destructor)) | ||
| 295 | (respawn? #t)))) | ||
| 296 | |||
| 297 | (define slim-service-type | ||
| 298 | (service-type (name 'slim) | ||
| 299 | (extensions | ||
| 300 | (list (service-extension dmd-root-service-type | ||
| 301 | slim-dmd-service) | ||
| 302 | (service-extension pam-root-service-type | ||
| 303 | slim-pam-service))))) | ||
| 304 | |||
| 215 | (define* (slim-service #:key (slim slim) | 305 | (define* (slim-service #:key (slim slim) |
| 216 | (allow-empty-passwords? #t) auto-login? | 306 | (allow-empty-passwords? #t) auto-login? |
| 217 | (default-user "") | 307 | (default-user "") |
| @@ -246,54 +336,14 @@ If @var{theme} is @code{#f}, the use the default log-in theme; otherwise | |||
| 246 | @var{theme} must be a gexp denoting the name of a directory containing the | 336 | @var{theme} must be a gexp denoting the name of a directory containing the |
| 247 | theme to use. In that case, @var{theme-name} specifies the name of the | 337 | theme to use. In that case, @var{theme-name} specifies the name of the |
| 248 | theme." | 338 | theme." |
| 249 | 339 | (service slim-service-type | |
| 250 | (define slim.cfg | 340 | (slim-configuration |
| 251 | (let ((xinitrc (xinitrc #:fallback-session auto-login-session))) | 341 | (slim slim) |
| 252 | (mixed-text-file "slim.cfg" " | 342 | (allow-empty-passwords? allow-empty-passwords?) |
| 253 | default_path /run/current-system/profile/bin | 343 | (auto-login? auto-login?) (default-user default-user) |
| 254 | default_xserver " startx " | 344 | (theme theme) (theme-name theme-name) |
| 255 | xserver_arguments :0 vt7 | 345 | (xauth xauth) (dmd dmd) (bash bash) |
| 256 | xauth_path " xauth "/bin/xauth | 346 | (auto-login-session auto-login-session) |
| 257 | authfile /var/run/slim.auth | 347 | (startx startx)))) |
| 258 | |||
| 259 | # The login command. '%session' is replaced by the chosen session name, one | ||
| 260 | # of the names specified in the 'sessions' setting: 'wmaker', 'xfce', etc. | ||
| 261 | login_cmd exec " xinitrc " %session | ||
| 262 | sessiondir /run/current-system/profile/share/xsessions | ||
| 263 | session_msg session (F1 to change): | ||
| 264 | |||
| 265 | halt_cmd " dmd "/sbin/halt | ||
| 266 | reboot_cmd " dmd "/sbin/reboot\n" | ||
| 267 | (if auto-login? | ||
| 268 | (string-append "auto_login yes\ndefault_user " default-user "\n") | ||
| 269 | "") | ||
| 270 | (if theme-name | ||
| 271 | (string-append "current_theme " theme-name "\n") | ||
| 272 | "")))) | ||
| 273 | |||
| 274 | (service | ||
| 275 | (documentation "Xorg display server") | ||
| 276 | (provision '(xorg-server)) | ||
| 277 | (requirement '(user-processes host-name udev)) | ||
| 278 | (start | ||
| 279 | #~(lambda () | ||
| 280 | ;; A stale lock file can prevent SLiM from starting, so remove it | ||
| 281 | ;; to be on the safe side. | ||
| 282 | (false-if-exception (delete-file "/var/run/slim.lock")) | ||
| 283 | |||
| 284 | (fork+exec-command | ||
| 285 | (list (string-append #$slim "/bin/slim") "-nodaemon") | ||
| 286 | #:environment-variables | ||
| 287 | (list (string-append "SLIM_CFGFILE=" #$slim.cfg) | ||
| 288 | #$@(if theme | ||
| 289 | (list #~(string-append "SLIM_THEMESDIR=" #$theme)) | ||
| 290 | #~()))))) | ||
| 291 | (stop #~(make-kill-destructor)) | ||
| 292 | (respawn? #t) | ||
| 293 | (pam-services | ||
| 294 | ;; Tell PAM about 'slim'. | ||
| 295 | (list (unix-pam-service | ||
| 296 | "slim" | ||
| 297 | #:allow-empty-passwords? allow-empty-passwords?))))) | ||
| 298 | 348 | ||
| 299 | ;;; xorg.scm ends here | 349 | ;;; xorg.scm ends here |
diff --git a/gnu/system.scm b/gnu/system.scm index 5eaafed6ae2..b32d26bc8e6 100644 --- a/gnu/system.scm +++ b/gnu/system.scm | |||
| @@ -87,8 +87,6 @@ | |||
| 87 | operating-system-locale-directory | 87 | operating-system-locale-directory |
| 88 | operating-system-boot-script | 88 | operating-system-boot-script |
| 89 | 89 | ||
| 90 | file-union | ||
| 91 | |||
| 92 | local-host-aliases | 90 | local-host-aliases |
| 93 | %setuid-programs | 91 | %setuid-programs |
| 94 | %base-packages | 92 | %base-packages |
| @@ -162,41 +160,6 @@ | |||
| 162 | 160 | ||
| 163 | 161 | ||
| 164 | ;;; | 162 | ;;; |
| 165 | ;;; Derivation. | ||
| 166 | ;;; | ||
| 167 | |||
| 168 | (define* (file-union name files) | ||
| 169 | "Return a derivation that builds a directory containing all of FILES. Each | ||
| 170 | item in FILES must be a list where the first element is the file name to use | ||
| 171 | in the new directory, and the second element is a gexp denoting the target | ||
| 172 | file." | ||
| 173 | (define builder | ||
| 174 | #~(begin | ||
| 175 | (mkdir #$output) | ||
| 176 | (chdir #$output) | ||
| 177 | #$@(map (match-lambda | ||
| 178 | ((target source) | ||
| 179 | #~(symlink #$source #$target))) | ||
| 180 | files))) | ||
| 181 | |||
| 182 | (gexp->derivation name builder)) | ||
| 183 | |||
| 184 | (define (directory-union name things) | ||
| 185 | "Return a directory that is the union of THINGS." | ||
| 186 | (match things | ||
| 187 | ((one) | ||
| 188 | ;; Only one thing; return it. | ||
| 189 | (with-monad %store-monad (return one))) | ||
| 190 | (_ | ||
| 191 | (gexp->derivation name | ||
| 192 | #~(begin | ||
| 193 | (use-modules (guix build union)) | ||
| 194 | (union-build #$output '#$things)) | ||
| 195 | #:modules '((guix build union)) | ||
| 196 | #:local-build? #t)))) | ||
| 197 | |||
| 198 | |||
| 199 | ;;; | ||
| 200 | ;;; Services. | 163 | ;;; Services. |
| 201 | ;;; | 164 | ;;; |
| 202 | 165 | ||
| @@ -244,18 +207,7 @@ as 'needed-for-boot'." | |||
| 244 | (string->symbol (mapped-device-target md)))) | 207 | (string->symbol (mapped-device-target md)))) |
| 245 | (device-mappings fs)))) | 208 | (device-mappings fs)))) |
| 246 | 209 | ||
| 247 | (map (lambda (fs) | 210 | (map file-system-service file-systems)) |
| 248 | (match fs | ||
| 249 | (($ <file-system> device title target type flags opts | ||
| 250 | #f check? create?) | ||
| 251 | (file-system-service device target type | ||
| 252 | #:title title | ||
| 253 | #:requirements (requirements fs) | ||
| 254 | #:check? check? | ||
| 255 | #:create-mount-point? create? | ||
| 256 | #:options opts | ||
| 257 | #:flags flags)))) | ||
| 258 | file-systems)) | ||
| 259 | 211 | ||
| 260 | (define (mapped-device-user device file-systems) | 212 | (define (mapped-device-user device file-systems) |
| 261 | "Return a file system among FILE-SYSTEMS that uses DEVICE, or #f." | 213 | "Return a file system among FILE-SYSTEMS that uses DEVICE, or #f." |
| @@ -302,10 +254,11 @@ from the initrd." | |||
| 302 | "Return the list of swap services for OS." | 254 | "Return the list of swap services for OS." |
| 303 | (map swap-service (operating-system-swap-devices os))) | 255 | (map swap-service (operating-system-swap-devices os))) |
| 304 | 256 | ||
| 305 | (define (essential-services os) | 257 | (define* (essential-services os #:key container?) |
| 306 | "Return the list of essential services for OS. These are special services | 258 | "Return the list of essential services for OS. These are special services |
| 307 | that implement part of what's declared in OS are responsible for low-level | 259 | that implement part of what's declared in OS are responsible for low-level |
| 308 | bookkeeping." | 260 | bookkeeping. CONTAINER? determines whether to return the list of services for |
| 261 | a container or that of a \"bare metal\" system." | ||
| 309 | (define known-fs | 262 | (define known-fs |
| 310 | (map file-system-mount-point (operating-system-file-systems os))) | 263 | (map file-system-mount-point (operating-system-file-systems os))) |
| 311 | 264 | ||
| @@ -315,17 +268,36 @@ bookkeeping." | |||
| 315 | (unmount (user-unmount-service known-fs)) | 268 | (unmount (user-unmount-service known-fs)) |
| 316 | (swaps (swap-services os)) | 269 | (swaps (swap-services os)) |
| 317 | (procs (user-processes-service | 270 | (procs (user-processes-service |
| 318 | (map (compose first service-provision) | 271 | (map service-parameters other-fs))) |
| 319 | other-fs))) | ||
| 320 | (host-name (host-name-service (operating-system-host-name os)))) | 272 | (host-name (host-name-service (operating-system-host-name os)))) |
| 321 | (cons* host-name procs root-fs unmount | 273 | (cons* %boot-service |
| 322 | (append other-fs mappings swaps)))) | 274 | |
| 323 | 275 | ;; %DMD-ROOT-SERVICE must come first so that the gexp that execs | |
| 324 | (define (operating-system-services os) | 276 | ;; dmd comes last in the boot script (XXX). |
| 277 | %dmd-root-service %activation-service | ||
| 278 | |||
| 279 | (pam-root-service (operating-system-pam-services os)) | ||
| 280 | (account-service (append (operating-system-accounts os) | ||
| 281 | (operating-system-groups os)) | ||
| 282 | (operating-system-skeletons os)) | ||
| 283 | (operating-system-etc-service os) | ||
| 284 | host-name procs root-fs unmount | ||
| 285 | (service setuid-program-service-type | ||
| 286 | (operating-system-setuid-programs os)) | ||
| 287 | (append other-fs mappings swaps | ||
| 288 | |||
| 289 | ;; Add the firmware service, unless we are building for a | ||
| 290 | ;; container. | ||
| 291 | (if container? | ||
| 292 | '() | ||
| 293 | (list (service firmware-service-type | ||
| 294 | (operating-system-firmware os)))))))) | ||
| 295 | |||
| 296 | (define* (operating-system-services os #:key container?) | ||
| 325 | "Return all the services of OS, including \"internal\" services that do not | 297 | "Return all the services of OS, including \"internal\" services that do not |
| 326 | explicitly appear in OS." | 298 | explicitly appear in OS." |
| 327 | (append (operating-system-user-services os) | 299 | (append (operating-system-user-services os) |
| 328 | (essential-services os))) | 300 | (essential-services os #:container? container?))) |
| 329 | 301 | ||
| 330 | 302 | ||
| 331 | ;;; | 303 | ;;; |
| @@ -388,28 +360,27 @@ This is the GNU system. Welcome.\n") | |||
| 388 | (define (emacs-site-file) | 360 | (define (emacs-site-file) |
| 389 | "Return the Emacs 'site-start.el' file. That file contains the necessary | 361 | "Return the Emacs 'site-start.el' file. That file contains the necessary |
| 390 | settings for 'guix.el' to work out-of-the-box." | 362 | settings for 'guix.el' to work out-of-the-box." |
| 391 | (gexp->file "site-start.el" | 363 | (scheme-file "site-start.el" |
| 392 | #~(progn | 364 | #~(progn |
| 393 | ;; Add the "normal" elisp directory to the search path; | 365 | ;; Add the "normal" elisp directory to the search path; |
| 394 | ;; guix.el may be there. | 366 | ;; guix.el may be there. |
| 395 | (add-to-list | 367 | (add-to-list |
| 396 | 'load-path | 368 | 'load-path |
| 397 | "/run/current-system/profile/share/emacs/site-lisp") | 369 | "/run/current-system/profile/share/emacs/site-lisp") |
| 398 | 370 | ||
| 399 | ;; Attempt to load guix.el. | 371 | ;; Attempt to load guix.el. |
| 400 | (require 'guix-init nil t) | 372 | (require 'guix-init nil t) |
| 401 | 373 | ||
| 402 | ;; Attempt to load geiser. | 374 | ;; Attempt to load geiser. |
| 403 | (require 'geiser-install nil t)))) | 375 | (require 'geiser-install nil t)))) |
| 404 | 376 | ||
| 405 | (define (emacs-site-directory) | 377 | (define (emacs-site-directory) |
| 406 | "Return the Emacs site directory, aka. /etc/emacs." | 378 | "Return the Emacs site directory, aka. /etc/emacs." |
| 407 | (mlet %store-monad ((file (emacs-site-file))) | 379 | (computed-file "emacs" |
| 408 | (gexp->derivation "emacs" | 380 | #~(begin |
| 409 | #~(begin | 381 | (mkdir #$output) |
| 410 | (mkdir #$output) | 382 | (chdir #$output) |
| 411 | (chdir #$output) | 383 | (symlink #$(emacs-site-file) "site-start.el")))) |
| 412 | (symlink #$file "site-start.el"))))) | ||
| 413 | 384 | ||
| 414 | (define (user-shells os) | 385 | (define (user-shells os) |
| 415 | "Return the list of all the shells used by the accounts of OS. These may be | 386 | "Return the list of all the shells used by the accounts of OS. These may be |
| @@ -417,49 +388,43 @@ gexps or strings." | |||
| 417 | (map user-account-shell (operating-system-accounts os))) | 388 | (map user-account-shell (operating-system-accounts os))) |
| 418 | 389 | ||
| 419 | (define (shells-file shells) | 390 | (define (shells-file shells) |
| 420 | "Return a derivation that builds a shell list for use as /etc/shells based | 391 | "Return a file-like object that builds a shell list for use as /etc/shells |
| 421 | on SHELLS. /etc/shells is used by xterm, polkit, and other programs." | 392 | based on SHELLS. /etc/shells is used by xterm, polkit, and other programs." |
| 422 | (gexp->derivation "shells" | 393 | (computed-file "shells" |
| 423 | #~(begin | 394 | #~(begin |
| 424 | (use-modules (srfi srfi-1)) | 395 | (use-modules (srfi srfi-1)) |
| 425 | 396 | ||
| 426 | (define shells | 397 | (define shells |
| 427 | (delete-duplicates (list #$@shells))) | 398 | (delete-duplicates (list #$@shells))) |
| 428 | 399 | ||
| 429 | (call-with-output-file #$output | 400 | (call-with-output-file #$output |
| 430 | (lambda (port) | 401 | (lambda (port) |
| 431 | (display "\ | 402 | (display "\ |
| 432 | /bin/sh | 403 | /bin/sh |
| 433 | /run/current-system/profile/bin/sh | 404 | /run/current-system/profile/bin/sh |
| 434 | /run/current-system/profile/bin/bash\n" port) | 405 | /run/current-system/profile/bin/bash\n" port) |
| 435 | (for-each (lambda (shell) | 406 | (for-each (lambda (shell) |
| 436 | (display shell port) | 407 | (display shell port) |
| 437 | (newline port)) | 408 | (newline port)) |
| 438 | shells)))))) | 409 | shells)))))) |
| 439 | 410 | ||
| 440 | (define* (etc-directory #:key | 411 | (define* (operating-system-etc-service os) |
| 441 | (locale "C") (timezone "Europe/Paris") | 412 | "Return a <service> that builds containing the static part of the /etc |
| 442 | (issue "Hello!\n") | 413 | directory." |
| 443 | (skeletons '()) | 414 | (let ((login.defs (plain-file "login.defs" "# Empty for now.\n")) |
| 444 | (pam-services '()) | 415 | |
| 445 | (profile "/run/current-system/profile") | 416 | (shells (shells-file (user-shells os))) |
| 446 | hosts-file nss (shells '()) | 417 | (emacs (emacs-site-directory)) |
| 447 | (sudoers-file (plain-file "sudoers" ""))) | 418 | (issue (plain-file "issue" (operating-system-issue os))) |
| 448 | "Return a derivation that builds the static part of the /etc directory." | 419 | (nsswitch (plain-file "nsswitch.conf" |
| 449 | (mlet* %store-monad | 420 | (name-service-switch->string |
| 450 | ((pam.d -> (pam-services->directory pam-services)) | 421 | (operating-system-name-service-switch os)))) |
| 451 | (login.defs (text-file "login.defs" "# Empty for now.\n")) | 422 | |
| 452 | (shells (shells-file shells)) | 423 | ;; Startup file for POSIX-compliant login shells, which set system-wide |
| 453 | (emacs (emacs-site-directory)) | 424 | ;; environment variables. |
| 454 | (issue (text-file "issue" issue)) | 425 | (profile (mixed-text-file "profile" "\ |
| 455 | (nsswitch (text-file "nsswitch.conf" | 426 | export LANG=\"" (operating-system-locale os) "\" |
| 456 | (name-service-switch->string nss))) | 427 | export TZ=\"" (operating-system-timezone os) "\" |
| 457 | |||
| 458 | ;; Startup file for POSIX-compliant login shells, which set system-wide | ||
| 459 | ;; environment variables. | ||
| 460 | (profile (text-file* "profile" "\ | ||
| 461 | export LANG=\"" locale "\" | ||
| 462 | export TZ=\"" timezone "\" | ||
| 463 | export TZDIR=\"" tzdata "/share/zoneinfo\" | 428 | export TZDIR=\"" tzdata "/share/zoneinfo\" |
| 464 | 429 | ||
| 465 | # Tell 'modprobe' & co. where to look for modules. | 430 | # Tell 'modprobe' & co. where to look for modules. |
| @@ -516,7 +481,7 @@ then | |||
| 516 | fi | 481 | fi |
| 517 | ")) | 482 | ")) |
| 518 | 483 | ||
| 519 | (bashrc (text-file "bashrc" "\ | 484 | (bashrc (plain-file "bashrc" "\ |
| 520 | # Bash-specific initialization. | 485 | # Bash-specific initialization. |
| 521 | 486 | ||
| 522 | # The 'bash-completion' package. | 487 | # The 'bash-completion' package. |
| @@ -526,25 +491,23 @@ then | |||
| 526 | # completion loader that searches its own completion files as well | 491 | # completion loader that searches its own completion files as well |
| 527 | # as those in ~/.guix-profile and /run/current-system/profile. | 492 | # as those in ~/.guix-profile and /run/current-system/profile. |
| 528 | source /run/current-system/profile/etc/profile.d/bash_completion.sh | 493 | source /run/current-system/profile/etc/profile.d/bash_completion.sh |
| 529 | fi\n")) | 494 | fi\n"))) |
| 530 | (skel -> (skeleton-directory skeletons))) | 495 | (etc-service |
| 531 | (file-union "etc" | 496 | `(("services" ,#~(string-append #$net-base "/etc/services")) |
| 532 | `(("services" ,#~(string-append #$net-base "/etc/services")) | 497 | ("protocols" ,#~(string-append #$net-base "/etc/protocols")) |
| 533 | ("protocols" ,#~(string-append #$net-base "/etc/protocols")) | 498 | ("rpc" ,#~(string-append #$net-base "/etc/rpc")) |
| 534 | ("rpc" ,#~(string-append #$net-base "/etc/rpc")) | 499 | ("emacs" ,#~#$emacs) |
| 535 | ("emacs" ,#~#$emacs) | 500 | ("login.defs" ,#~#$login.defs) |
| 536 | ("pam.d" ,#~#$pam.d) | 501 | ("issue" ,#~#$issue) |
| 537 | ("login.defs" ,#~#$login.defs) | 502 | ("nsswitch.conf" ,#~#$nsswitch) |
| 538 | ("issue" ,#~#$issue) | 503 | ("shells" ,#~#$shells) |
| 539 | ("nsswitch.conf" ,#~#$nsswitch) | 504 | ("profile" ,#~#$profile) |
| 540 | ("skel" ,#~#$skel) | 505 | ("bashrc" ,#~#$bashrc) |
| 541 | ("shells" ,#~#$shells) | 506 | ("hosts" ,#~#$(or (operating-system-hosts-file os) |
| 542 | ("profile" ,#~#$profile) | 507 | (default-/etc/hosts (operating-system-host-name os)))) |
| 543 | ("bashrc" ,#~#$bashrc) | 508 | ("localtime" ,#~(string-append #$tzdata "/share/zoneinfo/" |
| 544 | ("hosts" ,#~#$hosts-file) | 509 | #$(operating-system-timezone os))) |
| 545 | ("localtime" ,#~(string-append #$tzdata "/share/zoneinfo/" | 510 | ("sudoers" ,(operating-system-sudoers-file os)))))) |
| 546 | #$timezone)) | ||
| 547 | ("sudoers" ,sudoers-file))))) | ||
| 548 | 511 | ||
| 549 | (define (operating-system-profile os) | 512 | (define (operating-system-profile os) |
| 550 | "Return a derivation that builds the system profile of OS." | 513 | "Return a derivation that builds the system profile of OS." |
| @@ -561,18 +524,14 @@ fi\n")) | |||
| 561 | (home-directory "/root"))) | 524 | (home-directory "/root"))) |
| 562 | 525 | ||
| 563 | (define (operating-system-accounts os) | 526 | (define (operating-system-accounts os) |
| 564 | "Return the user accounts for OS, including an obligatory 'root' account." | 527 | "Return the user accounts for OS, including an obligatory 'root' account, |
| 565 | (define users | 528 | and excluding accounts requested by services." |
| 566 | ;; Make sure there's a root account. | 529 | ;; Make sure there's a root account. |
| 567 | (if (find (lambda (user) | 530 | (if (find (lambda (user) |
| 568 | (and=> (user-account-uid user) zero?)) | 531 | (and=> (user-account-uid user) zero?)) |
| 569 | (operating-system-users os)) | 532 | (operating-system-users os)) |
| 570 | (operating-system-users os) | 533 | (operating-system-users os) |
| 571 | (cons %root-account (operating-system-users os)))) | 534 | (cons %root-account (operating-system-users os)))) |
| 572 | |||
| 573 | (append users | ||
| 574 | (append-map service-user-accounts | ||
| 575 | (operating-system-services os)))) | ||
| 576 | 535 | ||
| 577 | (define (maybe-string->file file-name thing) | 536 | (define (maybe-string->file file-name thing) |
| 578 | "If THING is a string, return a <plain-file> with THING as its content. | 537 | "If THING is a string, return a <plain-file> with THING as its content. |
| @@ -607,31 +566,9 @@ use 'plain-file' instead~%") | |||
| 607 | 566 | ||
| 608 | (define (operating-system-etc-directory os) | 567 | (define (operating-system-etc-directory os) |
| 609 | "Return that static part of the /etc directory of OS." | 568 | "Return that static part of the /etc directory of OS." |
| 610 | (mlet* %store-monad | 569 | (etc-directory |
| 611 | ((services -> (operating-system-services os)) | 570 | (fold-services (operating-system-services os) |
| 612 | (pam-services -> | 571 | #:target-type etc-service-type))) |
| 613 | ;; Services known to PAM. | ||
| 614 | (append (operating-system-pam-services os) | ||
| 615 | (append-map service-pam-services services))) | ||
| 616 | (profile-drv (operating-system-profile os)) | ||
| 617 | (skeletons (operating-system-skeletons os)) | ||
| 618 | (/etc/hosts (maybe-file->monadic | ||
| 619 | "hosts" | ||
| 620 | (or (operating-system-hosts-file os) | ||
| 621 | (default-/etc/hosts (operating-system-host-name os))))) | ||
| 622 | (shells -> (user-shells os))) | ||
| 623 | (etc-directory #:pam-services pam-services | ||
| 624 | #:skeletons skeletons | ||
| 625 | #:issue (operating-system-issue os) | ||
| 626 | #:locale (operating-system-locale os) | ||
| 627 | #:nss (operating-system-name-service-switch os) | ||
| 628 | #:timezone (operating-system-timezone os) | ||
| 629 | #:hosts-file /etc/hosts | ||
| 630 | #:shells shells | ||
| 631 | #:sudoers-file (maybe-string->file | ||
| 632 | "sudoers" | ||
| 633 | (operating-system-sudoers-file os)) | ||
| 634 | #:profile profile-drv))) | ||
| 635 | 572 | ||
| 636 | (define %setuid-programs | 573 | (define %setuid-programs |
| 637 | ;; Default set of setuid-root programs. | 574 | ;; Default set of setuid-root programs. |
| @@ -652,176 +589,23 @@ use 'plain-file' instead~%") | |||
| 652 | root ALL=(ALL) ALL | 589 | root ALL=(ALL) ALL |
| 653 | %wheel ALL=(ALL) ALL\n")) | 590 | %wheel ALL=(ALL) ALL\n")) |
| 654 | 591 | ||
| 655 | (define (user-group->gexp group) | ||
| 656 | "Turn GROUP, a <user-group> object, into a list-valued gexp suitable for | ||
| 657 | 'active-groups'." | ||
| 658 | #~(list #$(user-group-name group) | ||
| 659 | #$(user-group-password group) | ||
| 660 | #$(user-group-id group) | ||
| 661 | #$(user-group-system? group))) | ||
| 662 | |||
| 663 | (define (user-account->gexp account) | ||
| 664 | "Turn ACCOUNT, a <user-account> object, into a list-valued gexp suitable for | ||
| 665 | 'activate-users'." | ||
| 666 | #~`(#$(user-account-name account) | ||
| 667 | #$(user-account-uid account) | ||
| 668 | #$(user-account-group account) | ||
| 669 | #$(user-account-supplementary-groups account) | ||
| 670 | #$(user-account-comment account) | ||
| 671 | #$(user-account-home-directory account) | ||
| 672 | ,#$(user-account-shell account) ; this one is a gexp | ||
| 673 | #$(user-account-password account) | ||
| 674 | #$(user-account-system? account))) | ||
| 675 | |||
| 676 | (define (modprobe-wrapper) | ||
| 677 | "Return a wrapper for the 'modprobe' command that knows where modules live. | ||
| 678 | |||
| 679 | This wrapper is typically invoked by the Linux kernel ('call_modprobe', in | ||
| 680 | kernel/kmod.c), a situation where the 'LINUX_MODULE_DIRECTORY' environment | ||
| 681 | variable is not set---hence the need for this wrapper." | ||
| 682 | (let ((modprobe "/run/current-system/profile/bin/modprobe")) | ||
| 683 | (gexp->script "modprobe" | ||
| 684 | #~(begin | ||
| 685 | (setenv "LINUX_MODULE_DIRECTORY" | ||
| 686 | "/run/booted-system/kernel/lib/modules") | ||
| 687 | (apply execl #$modprobe | ||
| 688 | (cons #$modprobe (cdr (command-line)))))))) | ||
| 689 | |||
| 690 | (define* (operating-system-activation-script os #:key container?) | 592 | (define* (operating-system-activation-script os #:key container?) |
| 691 | "Return the activation script for OS---i.e., the code that \"activates\" the | 593 | "Return the activation script for OS---i.e., the code that \"activates\" the |
| 692 | stateful part of OS, including user accounts and groups, special directories, | 594 | stateful part of OS, including user accounts and groups, special directories, |
| 693 | etc." | 595 | etc." |
| 694 | (define %modules | 596 | (let* ((services (operating-system-services os #:container? container?)) |
| 695 | '((gnu build activation) | 597 | (activation (fold-services services |
| 696 | (gnu build linux-boot) | 598 | #:target-type activation-service-type))) |
| 697 | (gnu build linux-modules) | 599 | (activation-service->script activation))) |
| 698 | (gnu build file-systems) | ||
| 699 | (guix build utils) | ||
| 700 | (guix build syscalls) | ||
| 701 | (guix elf))) | ||
| 702 | |||
| 703 | (define (service-activations services) | ||
| 704 | ;; Return the activation scripts for SERVICES. | ||
| 705 | (let ((gexps (filter-map service-activate services))) | ||
| 706 | (sequence %store-monad (map (cut gexp->file "activate-service.scm" <>) | ||
| 707 | gexps)))) | ||
| 708 | |||
| 709 | (mlet* %store-monad ((services -> (operating-system-services os)) | ||
| 710 | (actions (service-activations services)) | ||
| 711 | (etc (operating-system-etc-directory os)) | ||
| 712 | (modules (imported-modules %modules)) | ||
| 713 | (compiled (compiled-modules %modules)) | ||
| 714 | (modprobe (modprobe-wrapper)) | ||
| 715 | (firmware (directory-union | ||
| 716 | "firmware" (operating-system-firmware os))) | ||
| 717 | (accounts -> (operating-system-accounts os))) | ||
| 718 | (define setuid-progs | ||
| 719 | (operating-system-setuid-programs os)) | ||
| 720 | |||
| 721 | (define user-specs | ||
| 722 | (map user-account->gexp accounts)) | ||
| 723 | |||
| 724 | (define groups | ||
| 725 | (append (operating-system-groups os) | ||
| 726 | (append-map service-user-groups services))) | ||
| 727 | |||
| 728 | (define group-specs | ||
| 729 | (map user-group->gexp groups)) | ||
| 730 | |||
| 731 | (assert-valid-users/groups accounts groups) | ||
| 732 | |||
| 733 | (gexp->file "activate" | ||
| 734 | #~(begin | ||
| 735 | (eval-when (expand load eval) | ||
| 736 | ;; Make sure 'use-modules' below succeeds. | ||
| 737 | (set! %load-path (cons #$modules %load-path)) | ||
| 738 | (set! %load-compiled-path | ||
| 739 | (cons #$compiled %load-compiled-path))) | ||
| 740 | |||
| 741 | (use-modules (gnu build activation)) | ||
| 742 | |||
| 743 | ;; Make sure /bin/sh is valid and current. | ||
| 744 | (activate-/bin/sh | ||
| 745 | (string-append #$(canonical-package bash) | ||
| 746 | "/bin/sh")) | ||
| 747 | |||
| 748 | ;; Populate /etc. | ||
| 749 | (activate-etc #$etc) | ||
| 750 | |||
| 751 | ;; Add users and user groups. | ||
| 752 | (setenv "PATH" | ||
| 753 | (string-append #$(@ (gnu packages admin) shadow) | ||
| 754 | "/sbin")) | ||
| 755 | (activate-users+groups (list #$@user-specs) | ||
| 756 | (list #$@group-specs)) | ||
| 757 | |||
| 758 | ;; Activate setuid programs. | ||
| 759 | (activate-setuid-programs (list #$@setuid-progs)) | ||
| 760 | |||
| 761 | ;; Tell the kernel to use our 'modprobe' command. | ||
| 762 | (activate-modprobe #$modprobe) | ||
| 763 | |||
| 764 | ;; Tell the kernel where firmware is, unless we are | ||
| 765 | ;; activating a container. | ||
| 766 | #$@(if container? | ||
| 767 | #~() | ||
| 768 | ;; Tell the kernel where firmware is. | ||
| 769 | #~((activate-firmware | ||
| 770 | (string-append #$firmware "/lib/firmware")) | ||
| 771 | ;; Let users debug their own processes! | ||
| 772 | (activate-ptrace-attach))) | ||
| 773 | |||
| 774 | ;; Run the services' activation snippets. | ||
| 775 | ;; TODO: Use 'load-compiled'. | ||
| 776 | (for-each primitive-load '#$actions) | ||
| 777 | |||
| 778 | ;; Set up /run/current-system. | ||
| 779 | (activate-current-system))))) | ||
| 780 | 600 | ||
| 781 | (define* (operating-system-boot-script os #:key container?) | 601 | (define* (operating-system-boot-script os #:key container?) |
| 782 | "Return the boot script for OS---i.e., the code started by the initrd once | 602 | "Return the boot script for OS---i.e., the code started by the initrd once |
| 783 | we're running in the final root. When CONTAINER? is true, skip all | 603 | we're running in the final root. When CONTAINER? is true, skip all |
| 784 | hardware-related operations as necessary when booting a Linux container." | 604 | hardware-related operations as necessary when booting a Linux container." |
| 785 | (mlet* %store-monad ((services -> (operating-system-services os)) | 605 | (let* ((services (operating-system-services os #:container? container?)) |
| 786 | (activate (operating-system-activation-script os)) | 606 | (boot (fold-services services))) |
| 787 | (dmd-conf (dmd-configuration-file services))) | 607 | ;; BOOT is the script as a monadic value. |
| 788 | (gexp->file "boot" | 608 | (service-parameters boot))) |
| 789 | #~(begin | ||
| 790 | (use-modules (guix build utils)) | ||
| 791 | |||
| 792 | ;; Clean out /tmp and /var/run. | ||
| 793 | ;; | ||
| 794 | ;; XXX This needs to happen before service activations, so | ||
| 795 | ;; it has to be here, but this also implicitly assumes | ||
| 796 | ;; that /tmp and /var/run are on the root partition. | ||
| 797 | (false-if-exception (delete-file-recursively "/tmp")) | ||
| 798 | (false-if-exception (delete-file-recursively "/var/run")) | ||
| 799 | (false-if-exception (mkdir "/tmp")) | ||
| 800 | (false-if-exception (chmod "/tmp" #o1777)) | ||
| 801 | (false-if-exception (mkdir "/var/run")) | ||
| 802 | (false-if-exception (chmod "/var/run" #o755)) | ||
| 803 | |||
| 804 | ;; Activate the system. | ||
| 805 | ;; TODO: Use 'load-compiled'. | ||
| 806 | (primitive-load #$activate) | ||
| 807 | |||
| 808 | ;; Keep track of the booted system. | ||
| 809 | (false-if-exception (delete-file "/run/booted-system")) | ||
| 810 | (symlink (readlink "/run/current-system") | ||
| 811 | "/run/booted-system") | ||
| 812 | |||
| 813 | ;; Close any remaining open file descriptors to be on the | ||
| 814 | ;; safe side. This must be the very last thing we do, | ||
| 815 | ;; because Guile has internal FDs such as 'sleep_pipe' | ||
| 816 | ;; that need to be alive. | ||
| 817 | (let loop ((fd 3)) | ||
| 818 | (when (< fd 1024) | ||
| 819 | (false-if-exception (close-fdes fd)) | ||
| 820 | (loop (+ 1 fd)))) | ||
| 821 | |||
| 822 | ;; Start dmd. | ||
| 823 | (execl (string-append #$dmd "/bin/dmd") | ||
| 824 | "dmd" "--config" #$dmd-conf))))) | ||
| 825 | 609 | ||
| 826 | (define (operating-system-root-file-system os) | 610 | (define (operating-system-root-file-system os) |
| 827 | "Return the root file system of OS." | 611 | "Return the root file system of OS." |
| @@ -908,19 +692,20 @@ this file is the reconstruction of GRUB menu entries for old configurations." | |||
| 908 | "Return a derivation that builds OS." | 692 | "Return a derivation that builds OS." |
| 909 | (mlet* %store-monad | 693 | (mlet* %store-monad |
| 910 | ((profile (operating-system-profile os)) | 694 | ((profile (operating-system-profile os)) |
| 911 | (etc (operating-system-etc-directory os)) | 695 | (etc -> (operating-system-etc-directory os)) |
| 912 | (boot (operating-system-boot-script os)) | 696 | (boot (operating-system-boot-script os)) |
| 913 | (kernel -> (operating-system-kernel os)) | 697 | (kernel -> (operating-system-kernel os)) |
| 914 | (initrd (operating-system-initrd-file os)) | 698 | (initrd (operating-system-initrd-file os)) |
| 915 | (locale (operating-system-locale-directory os)) | 699 | (locale (operating-system-locale-directory os)) |
| 916 | (params (operating-system-parameters-file os))) | 700 | (params (operating-system-parameters-file os))) |
| 917 | (file-union "system" | 701 | (lower-object |
| 918 | `(("boot" ,#~#$boot) | 702 | (file-union "system" |
| 919 | ("kernel" ,#~#$kernel) | 703 | `(("boot" ,#~#$boot) |
| 920 | ("parameters" ,#~#$params) | 704 | ("kernel" ,#~#$kernel) |
| 921 | ("initrd" ,initrd) | 705 | ("parameters" ,#~#$params) |
| 922 | ("profile" ,#~#$profile) | 706 | ("initrd" ,initrd) |
| 923 | ("locale" ,#~#$locale) ;used by libc | 707 | ("profile" ,#~#$profile) |
| 924 | ("etc" ,#~#$etc))))) | 708 | ("locale" ,#~#$locale) ;used by libc |
| 709 | ("etc" ,#~#$etc)))))) | ||
| 925 | 710 | ||
| 926 | ;;; system.scm ends here | 711 | ;;; system.scm ends here |
diff --git a/gnu/system/install.scm b/gnu/system/install.scm index 560d64b5d4f..a91c5c3533f 100644 --- a/gnu/system/install.scm +++ b/gnu/system/install.scm | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #:use-module (guix monads) | 24 | #:use-module (guix monads) |
| 25 | #:use-module ((guix store) #:select (%store-prefix)) | 25 | #:use-module ((guix store) #:select (%store-prefix)) |
| 26 | #:use-module (guix profiles) | 26 | #:use-module (guix profiles) |
| 27 | #:use-module (gnu services dmd) | ||
| 27 | #:use-module (gnu packages admin) | 28 | #:use-module (gnu packages admin) |
| 28 | #:use-module (gnu packages bash) | 29 | #:use-module (gnu packages bash) |
| 29 | #:use-module (gnu packages linux) | 30 | #:use-module (gnu packages linux) |
| @@ -159,68 +160,74 @@ current store is on a RAM disk." | |||
| 159 | (mount "/.rw-store" #$(%store-prefix) "" MS_MOVE) | 160 | (mount "/.rw-store" #$(%store-prefix) "" MS_MOVE) |
| 160 | (rmdir "/.rw-store")))))) | 161 | (rmdir "/.rw-store")))))) |
| 161 | 162 | ||
| 163 | (define cow-store-service-type | ||
| 164 | (dmd-service-type | ||
| 165 | (lambda _ | ||
| 166 | (dmd-service | ||
| 167 | (requirement '(root-file-system user-processes)) | ||
| 168 | (provision '(cow-store)) | ||
| 169 | (documentation | ||
| 170 | "Make the store copy-on-write, with writes going to \ | ||
| 171 | the given target.") | ||
| 172 | |||
| 173 | ;; This is meant to be explicitly started by the user. | ||
| 174 | (auto-start? #f) | ||
| 175 | |||
| 176 | (start #~(case-lambda | ||
| 177 | ((target) | ||
| 178 | #$(make-cow-store #~target) | ||
| 179 | target) | ||
| 180 | (else | ||
| 181 | ;; Do nothing, and mark the service as stopped. | ||
| 182 | #f))) | ||
| 183 | (stop #~(lambda (target) | ||
| 184 | ;; Delete the temporary directory, but leave everything | ||
| 185 | ;; mounted as there may still be processes using it since | ||
| 186 | ;; 'user-processes' doesn't depend on us. The 'user-unmount' | ||
| 187 | ;; service will unmount TARGET eventually. | ||
| 188 | (delete-file-recursively | ||
| 189 | (string-append target #$%backing-directory)))))))) | ||
| 190 | |||
| 162 | (define (cow-store-service) | 191 | (define (cow-store-service) |
| 163 | "Return a service that makes the store copy-on-write, such that writes go to | 192 | "Return a service that makes the store copy-on-write, such that writes go to |
| 164 | the user's target storage device rather than on the RAM disk." | 193 | the user's target storage device rather than on the RAM disk." |
| 165 | ;; See <http://bugs.gnu.org/18061> for the initial report. | 194 | ;; See <http://bugs.gnu.org/18061> for the initial report. |
| 166 | (service | 195 | (service cow-store-service-type 'mooooh!)) |
| 167 | (requirement '(root-file-system user-processes)) | 196 | |
| 168 | (provision '(cow-store)) | 197 | |
| 169 | (documentation | 198 | (define (/etc/configuration-files _) |
| 170 | "Make the store copy-on-write, with writes going to \ | 199 | "Return a list of tuples representing configuration templates to add to |
| 171 | the given target.") | 200 | /etc." |
| 172 | 201 | (define (file f) | |
| 173 | ;; This is meant to be explicitly started by the user. | 202 | (local-file (search-path %load-path |
| 174 | (auto-start? #f) | 203 | (string-append "gnu/system/examples/" f)))) |
| 175 | 204 | ||
| 176 | (start #~(case-lambda | 205 | (define directory |
| 177 | ((target) | 206 | (computed-file "configuration-templates" |
| 178 | #$(make-cow-store #~target) | 207 | #~(begin |
| 179 | target) | 208 | (mkdir #$output) |
| 180 | (else | 209 | (for-each (lambda (file target) |
| 181 | ;; Do nothing, and mark the service as stopped. | 210 | (copy-file file |
| 182 | #f))) | 211 | (string-append #$output "/" |
| 183 | (stop #~(lambda (target) | 212 | target))) |
| 184 | ;; Delete the temporary directory, but leave everything | 213 | '(#$(file "bare-bones.tmpl") |
| 185 | ;; mounted as there may still be processes using it | 214 | #$(file "desktop.tmpl")) |
| 186 | ;; since 'user-processes' doesn't depend on us. The | 215 | '("bare-bones.scm" |
| 187 | ;; 'user-unmount' service will unmount TARGET | 216 | "desktop.scm")) |
| 188 | ;; eventually. | 217 | #t) |
| 189 | (delete-file-recursively | 218 | #:modules '((guix build utils)))) |
| 190 | (string-append target #$%backing-directory)))))) | 219 | |
| 191 | 220 | `(("configuration" ,directory))) | |
| 192 | (define (configuration-template-service) | 221 | |
| 193 | "Return a dummy service whose purpose is to install an operating system | 222 | (define configuration-template-service-type |
| 194 | configuration template file in the installation system." | 223 | (service-type (name 'configuration-template) |
| 195 | 224 | (extensions | |
| 196 | (define search | 225 | (list (service-extension etc-service-type |
| 197 | (cut search-path %load-path <>)) | 226 | /etc/configuration-files))))) |
| 198 | (define templates | 227 | |
| 199 | (map (match-lambda | 228 | (define %configuration-template-service |
| 200 | ((file '-> target) | 229 | (service configuration-template-service-type #t)) |
| 201 | (list (local-file (search file)) | ||
| 202 | (string-append "/etc/configuration/" target)))) | ||
| 203 | '(("gnu/system/examples/bare-bones.tmpl" -> "bare-bones.scm") | ||
| 204 | ("gnu/system/examples/desktop.tmpl" -> "desktop.scm")))) | ||
| 205 | |||
| 206 | (service | ||
| 207 | (requirement '(root-file-system)) | ||
| 208 | (provision '(os-config-template)) | ||
| 209 | (documentation | ||
| 210 | "This dummy service installs an OS configuration template.") | ||
| 211 | (start #~(const #t)) | ||
| 212 | (stop #~(const #f)) | ||
| 213 | (activate | ||
| 214 | #~(begin | ||
| 215 | (use-modules (ice-9 match) | ||
| 216 | (guix build utils)) | ||
| 217 | 230 | ||
| 218 | (mkdir-p "/etc/configuration") | ||
| 219 | (for-each (match-lambda | ||
| 220 | ((file target) | ||
| 221 | (unless (file-exists? target) | ||
| 222 | (copy-file file target)))) | ||
| 223 | '#$templates))))) | ||
| 224 | 231 | ||
| 225 | (define %nscd-minimal-caches | 232 | (define %nscd-minimal-caches |
| 226 | ;; Minimal in-memory caching policy for nscd. | 233 | ;; Minimal in-memory caching policy for nscd. |
| @@ -262,7 +269,7 @@ You have been warned. Thanks for being so brave. | |||
| 262 | (login-program (log-to-info)))) | 269 | (login-program (log-to-info)))) |
| 263 | 270 | ||
| 264 | ;; Documentation add-on. | 271 | ;; Documentation add-on. |
| 265 | (configuration-template-service) | 272 | %configuration-template-service |
| 266 | 273 | ||
| 267 | ;; A bunch of 'root' ttys. | 274 | ;; A bunch of 'root' ttys. |
| 268 | (normal-tty "tty3") | 275 | (normal-tty "tty3") |
| @@ -276,7 +283,7 @@ You have been warned. Thanks for being so brave. | |||
| 276 | ;; The build daemon. Register the hydra.gnu.org key as trusted. | 283 | ;; The build daemon. Register the hydra.gnu.org key as trusted. |
| 277 | ;; This allows the installation process to use substitutes by | 284 | ;; This allows the installation process to use substitutes by |
| 278 | ;; default. | 285 | ;; default. |
| 279 | (guix-service #:authorize-hydra-key? #t) | 286 | (guix-service (guix-configuration (authorize-key? #t))) |
| 280 | 287 | ||
| 281 | ;; Start udev so that useful device nodes are available. | 288 | ;; Start udev so that useful device nodes are available. |
| 282 | ;; Use device-mapper rules for cryptsetup & co; enable the CRDA for | 289 | ;; Use device-mapper rules for cryptsetup & co; enable the CRDA for |
diff --git a/gnu/system/linux.scm b/gnu/system/linux.scm index 10e72e905a5..cd14bc97be0 100644 --- a/gnu/system/linux.scm +++ b/gnu/system/linux.scm | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #:use-module (guix records) | 20 | #:use-module (guix records) |
| 21 | #:use-module (guix derivations) | 21 | #:use-module (guix derivations) |
| 22 | #:use-module (guix gexp) | 22 | #:use-module (guix gexp) |
| 23 | #:use-module (gnu services) | ||
| 23 | #:use-module (ice-9 match) | 24 | #:use-module (ice-9 match) |
| 24 | #:use-module (srfi srfi-1) | 25 | #:use-module (srfi srfi-1) |
| 25 | #:use-module (srfi srfi-26) | 26 | #:use-module (srfi srfi-26) |
| @@ -28,7 +29,10 @@ | |||
| 28 | pam-entry | 29 | pam-entry |
| 29 | pam-services->directory | 30 | pam-services->directory |
| 30 | unix-pam-service | 31 | unix-pam-service |
| 31 | base-pam-services)) | 32 | base-pam-services |
| 33 | |||
| 34 | pam-root-service-type | ||
| 35 | pam-root-service)) | ||
| 32 | 36 | ||
| 33 | ;;; Commentary: | 37 | ;;; Commentary: |
| 34 | ;;; | 38 | ;;; |
| @@ -98,8 +102,8 @@ dumped in /etc/pam.d/NAME, where NAME is the name of SERVICE." | |||
| 98 | 102 | ||
| 99 | (mkdir #$output) | 103 | (mkdir #$output) |
| 100 | (for-each (match-lambda | 104 | (for-each (match-lambda |
| 101 | ((name file) | 105 | ((name file) |
| 102 | (symlink file (string-append #$output "/" name)))) | 106 | (symlink file (string-append #$output "/" name)))) |
| 103 | 107 | ||
| 104 | ;; Since <pam-service> objects cannot be compared with | 108 | ;; Since <pam-service> objects cannot be compared with |
| 105 | ;; 'equal?' since they contain gexps, which contain | 109 | ;; 'equal?' since they contain gexps, which contain |
| @@ -188,4 +192,24 @@ authenticate to run COMMAND." | |||
| 188 | '("useradd" "userdel" "usermod" | 192 | '("useradd" "userdel" "usermod" |
| 189 | "groupadd" "groupdel" "groupmod")))) | 193 | "groupadd" "groupdel" "groupmod")))) |
| 190 | 194 | ||
| 195 | |||
| 196 | ;;; | ||
| 197 | ;;; PAM root service. | ||
| 198 | ;;; | ||
| 199 | |||
| 200 | (define (/etc-entry services) | ||
| 201 | `(("pam.d" ,(pam-services->directory services)))) | ||
| 202 | |||
| 203 | (define pam-root-service-type | ||
| 204 | (service-type (name 'pam) | ||
| 205 | (extensions (list (service-extension etc-service-type | ||
| 206 | /etc-entry))) | ||
| 207 | (compose concatenate) | ||
| 208 | (extend append))) | ||
| 209 | |||
| 210 | (define (pam-root-service base) | ||
| 211 | "The \"root\" PAM service, which collects <pam-service> instance and turns | ||
| 212 | them into a /etc/pam.d directory, including the <pam-service> listed in BASE." | ||
| 213 | (service pam-root-service-type base)) | ||
| 214 | |||
| 191 | ;;; linux.scm ends here | 215 | ;;; linux.scm ends here |
diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index ddd5f668743..3f49c1fc9f0 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm | |||
| @@ -22,12 +22,14 @@ | |||
| 22 | #:use-module (guix store) | 22 | #:use-module (guix store) |
| 23 | #:use-module (guix sets) | 23 | #:use-module (guix sets) |
| 24 | #:use-module (guix ui) | 24 | #:use-module (guix ui) |
| 25 | #:use-module (gnu services) | ||
| 25 | #:use-module ((gnu system file-systems) | 26 | #:use-module ((gnu system file-systems) |
| 26 | #:select (%tty-gid)) | 27 | #:select (%tty-gid)) |
| 27 | #:use-module ((gnu packages admin) | 28 | #:use-module ((gnu packages admin) |
| 28 | #:select (shadow)) | 29 | #:select (shadow)) |
| 29 | #:use-module (gnu packages bash) | 30 | #:use-module (gnu packages bash) |
| 30 | #:use-module (gnu packages guile-wm) | 31 | #:use-module (gnu packages guile-wm) |
| 32 | #:use-module (srfi srfi-1) | ||
| 31 | #:use-module (srfi srfi-26) | 33 | #:use-module (srfi srfi-26) |
| 32 | #:use-module (srfi srfi-34) | 34 | #:use-module (srfi srfi-34) |
| 33 | #:use-module (srfi srfi-35) | 35 | #:use-module (srfi srfi-35) |
| @@ -54,7 +56,9 @@ | |||
| 54 | skeleton-directory | 56 | skeleton-directory |
| 55 | %base-groups | 57 | %base-groups |
| 56 | %base-user-accounts | 58 | %base-user-accounts |
| 57 | assert-valid-users/groups)) | 59 | |
| 60 | account-service-type | ||
| 61 | account-service)) | ||
| 58 | 62 | ||
| 59 | ;;; Commentary: | 63 | ;;; Commentary: |
| 60 | ;;; | 64 | ;;; |
| @@ -87,31 +91,32 @@ | |||
| 87 | (system? user-group-system? ; Boolean | 91 | (system? user-group-system? ; Boolean |
| 88 | (default #f))) | 92 | (default #f))) |
| 89 | 93 | ||
| 94 | |||
| 90 | (define %base-groups | 95 | (define %base-groups |
| 91 | ;; Default set of groups. | 96 | ;; Default set of groups. |
| 92 | (let-syntax ((system-group (syntax-rules () | 97 | (let-syntax ((system-group (syntax-rules () |
| 93 | ((_ args ...) | 98 | ((_ args ...) |
| 94 | (user-group (system? #t) args ...))))) | 99 | (user-group (system? #t) args ...))))) |
| 95 | (list (system-group (name "root") (id 0)) | 100 | (list (system-group (name "root") (id 0)) |
| 96 | (system-group (name "wheel")) ; root-like users | 101 | (system-group (name "wheel")) ; root-like users |
| 97 | (system-group (name "users")) ; normal users | 102 | (system-group (name "users")) ; normal users |
| 98 | (system-group (name "nogroup")) ; for daemons etc. | 103 | (system-group (name "nogroup")) ; for daemons etc. |
| 99 | 104 | ||
| 100 | ;; The following groups are conventionally used by things like udev to | 105 | ;; The following groups are conventionally used by things like udev to |
| 101 | ;; control access to hardware devices. | 106 | ;; control access to hardware devices. |
| 102 | (system-group (name "tty") (id %tty-gid)) | 107 | (system-group (name "tty") (id %tty-gid)) |
| 103 | (system-group (name "dialout")) | 108 | (system-group (name "dialout")) |
| 104 | (system-group (name "kmem")) | 109 | (system-group (name "kmem")) |
| 105 | (system-group (name "input")) ; input devices, from udev | 110 | (system-group (name "input")) ; input devices, from udev |
| 106 | (system-group (name "video")) | 111 | (system-group (name "video")) |
| 107 | (system-group (name "audio")) | 112 | (system-group (name "audio")) |
| 108 | (system-group (name "netdev")) ; used in avahi-dbus.conf | 113 | (system-group (name "netdev")) ; used in avahi-dbus.conf |
| 109 | (system-group (name "lp")) | 114 | (system-group (name "lp")) |
| 110 | (system-group (name "disk")) | 115 | (system-group (name "disk")) |
| 111 | (system-group (name "floppy")) | 116 | (system-group (name "floppy")) |
| 112 | (system-group (name "cdrom")) | 117 | (system-group (name "cdrom")) |
| 113 | (system-group (name "tape")) | 118 | (system-group (name "tape")) |
| 114 | (system-group (name "kvm"))))) ; for /dev/kvm | 119 | (system-group (name "kvm"))))) ; for /dev/kvm |
| 115 | 120 | ||
| 116 | (define %base-user-accounts | 121 | (define %base-user-accounts |
| 117 | ;; List of standard user accounts. Note that "root" is a special case, so | 122 | ;; List of standard user accounts. Note that "root" is a special case, so |
| @@ -224,4 +229,81 @@ of user '~a' is undeclared") | |||
| 224 | (user-account-supplementary-groups user))) | 229 | (user-account-supplementary-groups user))) |
| 225 | users))) | 230 | users))) |
| 226 | 231 | ||
| 232 | |||
| 233 | ;;; | ||
| 234 | ;;; Service. | ||
| 235 | ;;; | ||
| 236 | |||
| 237 | (define (user-group->gexp group) | ||
| 238 | "Turn GROUP, a <user-group> object, into a list-valued gexp suitable for | ||
| 239 | 'active-groups'." | ||
| 240 | #~(list #$(user-group-name group) | ||
| 241 | #$(user-group-password group) | ||
| 242 | #$(user-group-id group) | ||
| 243 | #$(user-group-system? group))) | ||
| 244 | |||
| 245 | (define (user-account->gexp account) | ||
| 246 | "Turn ACCOUNT, a <user-account> object, into a list-valued gexp suitable for | ||
| 247 | 'activate-users'." | ||
| 248 | #~`(#$(user-account-name account) | ||
| 249 | #$(user-account-uid account) | ||
| 250 | #$(user-account-group account) | ||
| 251 | #$(user-account-supplementary-groups account) | ||
| 252 | #$(user-account-comment account) | ||
| 253 | #$(user-account-home-directory account) | ||
| 254 | ,#$(user-account-shell account) ; this one is a gexp | ||
| 255 | #$(user-account-password account) | ||
| 256 | #$(user-account-system? account))) | ||
| 257 | |||
| 258 | (define (account-activation accounts+groups) | ||
| 259 | "Return a gexp that activates ACCOUNTS+GROUPS, a list of <user-account> and | ||
| 260 | <user-group> objects. Raise an error if a user account refers to a undefined | ||
| 261 | group." | ||
| 262 | (define accounts | ||
| 263 | (filter user-account? accounts+groups)) | ||
| 264 | |||
| 265 | (define user-specs | ||
| 266 | (map user-account->gexp accounts)) | ||
| 267 | |||
| 268 | (define groups | ||
| 269 | (filter user-group? accounts+groups)) | ||
| 270 | |||
| 271 | (define group-specs | ||
| 272 | (map user-group->gexp groups)) | ||
| 273 | |||
| 274 | (assert-valid-users/groups accounts groups) | ||
| 275 | |||
| 276 | ;; Add users and user groups. | ||
| 277 | #~(begin | ||
| 278 | (setenv "PATH" | ||
| 279 | (string-append #$(@ (gnu packages admin) shadow) "/sbin")) | ||
| 280 | (activate-users+groups (list #$@user-specs) | ||
| 281 | (list #$@group-specs)))) | ||
| 282 | |||
| 283 | (define (etc-skel arguments) | ||
| 284 | "Filter out among ARGUMENTS things corresponding to skeletons, and return | ||
| 285 | the /etc/skel directory for those." | ||
| 286 | (let ((skels (filter pair? arguments))) | ||
| 287 | `(("skel" ,(skeleton-directory skels))))) | ||
| 288 | |||
| 289 | (define account-service-type | ||
| 290 | (service-type (name 'account) | ||
| 291 | |||
| 292 | ;; Concatenate <user-account>, <user-group>, and skeleton | ||
| 293 | ;; lists. | ||
| 294 | (compose concatenate) | ||
| 295 | (extend append) | ||
| 296 | |||
| 297 | (extensions | ||
| 298 | (list (service-extension activation-service-type | ||
| 299 | account-activation) | ||
| 300 | (service-extension etc-service-type | ||
| 301 | etc-skel))))) | ||
| 302 | |||
| 303 | (define (account-service accounts+groups skeletons) | ||
| 304 | "Return a <service> that takes care of user accounts and user groups, with | ||
| 305 | ACCOUNTS+GROUPS as its initial list of accounts and groups." | ||
| 306 | (service account-service-type | ||
| 307 | (append skeletons accounts+groups))) | ||
| 308 | |||
| 227 | ;;; shadow.scm ends here | 309 | ;;; shadow.scm ends here |
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in index c0f169eca4c..af46dac0e06 100644 --- a/po/guix/POTFILES.in +++ b/po/guix/POTFILES.in | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | # List of source files which contain translatable strings. | 1 | # List of source files which contain translatable strings. |
| 2 | # This should be source files of the various tools, and not package modules. | 2 | # This should be source files of the various tools, and not package modules. |
| 3 | gnu/packages.scm | 3 | gnu/packages.scm |
| 4 | gnu/services.scm | ||
| 4 | gnu/system.scm | 5 | gnu/system.scm |
| 5 | gnu/services/dmd.scm | 6 | gnu/services/dmd.scm |
| 6 | gnu/system/shadow.scm | 7 | gnu/system/shadow.scm |
diff --git a/tests/services.scm b/tests/services.scm new file mode 100644 index 00000000000..b4e2cb0b305 --- /dev/null +++ b/tests/services.scm | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (test-services) | ||
| 20 | #:use-module (gnu services) | ||
| 21 | #:use-module (srfi srfi-1) | ||
| 22 | #:use-module (srfi srfi-26) | ||
| 23 | #:use-module (srfi srfi-34) | ||
| 24 | #:use-module (srfi srfi-64)) | ||
| 25 | |||
| 26 | (test-begin "services") | ||
| 27 | |||
| 28 | (test-equal "fold-services" | ||
| 29 | ;; Make sure 'fold-services' returns the right result. The numbers come | ||
| 30 | ;; from services of type T3; 'xyz 60' comes from the service of type T2, | ||
| 31 | ;; where 60 = 15 × 4 = (1 + 2 + 3 + 4 + 5) × 4. | ||
| 32 | '(initial-value 5 4 3 2 1 xyz 60) | ||
| 33 | (let* ((t1 (service-type (name 't1) (extensions '()) | ||
| 34 | (compose concatenate) | ||
| 35 | (extend cons))) | ||
| 36 | (t2 (service-type (name 't2) | ||
| 37 | (extensions | ||
| 38 | (list (service-extension t1 | ||
| 39 | (cut list 'xyz <>)))) | ||
| 40 | (compose (cut reduce + 0 <>)) | ||
| 41 | (extend *))) | ||
| 42 | (t3 (service-type (name 't3) | ||
| 43 | (extensions | ||
| 44 | (list (service-extension t2 identity) | ||
| 45 | (service-extension t1 list))))) | ||
| 46 | (r (fold-services (cons* (service t1 'initial-value) | ||
| 47 | (service t2 4) | ||
| 48 | (map (lambda (x) | ||
| 49 | (service t3 x)) | ||
| 50 | (iota 5 1))) | ||
| 51 | #:target-type t1))) | ||
| 52 | (and (eq? (service-kind r) t1) | ||
| 53 | (service-parameters r)))) | ||
| 54 | |||
| 55 | (test-assert "fold-services, ambiguity" | ||
| 56 | (let* ((t1 (service-type (name 't1) (extensions '()) | ||
| 57 | (compose concatenate) | ||
| 58 | (extend cons))) | ||
| 59 | (t2 (service-type (name 't2) | ||
| 60 | (extensions | ||
| 61 | (list (service-extension t1 list))))) | ||
| 62 | (s (service t2 42))) | ||
| 63 | (guard (c ((ambiguous-target-service-error? c) | ||
| 64 | (and (eq? (ambiguous-target-service-error-target-type c) | ||
| 65 | t1) | ||
| 66 | (eq? (ambiguous-target-service-error-service c) | ||
| 67 | s)))) | ||
| 68 | (fold-services (list (service t1 'first) | ||
| 69 | (service t1 'second) | ||
| 70 | s) | ||
| 71 | #:target-type t1) | ||
| 72 | #f))) | ||
| 73 | |||
| 74 | (test-assert "fold-services, missing target" | ||
| 75 | (let* ((t1 (service-type (name 't1) (extensions '()))) | ||
| 76 | (t2 (service-type (name 't2) | ||
| 77 | (extensions | ||
| 78 | (list (service-extension t1 list))))) | ||
| 79 | (s (service t2 42))) | ||
| 80 | (guard (c ((missing-target-service-error? c) | ||
| 81 | (and (eq? (missing-target-service-error-target-type c) | ||
| 82 | t1) | ||
| 83 | (eq? (missing-target-service-error-service c) | ||
| 84 | s)))) | ||
| 85 | (fold-services (list s) #:target-type t1) | ||
| 86 | #f))) | ||
| 87 | |||
| 88 | (test-end) | ||
| 89 | |||
| 90 | |||
| 91 | (exit (= (test-runner-fail-count (test-runner-current)) 0)) | ||
