123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908 |
- ;;; GNU Guix --- Functional package management for GNU
- ;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
- ;;; Copyright © 2015, 2016 Alex Kost <alezost@gmail.com>
- ;;; Copyright © 2015, 2016 Mark H Weaver <mhw@netris.org>
- ;;; Copyright © 2015 Sou Bunnbu <iyzsong@gmail.com>
- ;;; Copyright © 2016, 2017 Leo Famulari <leo@famulari.name>
- ;;; Copyright © 2016 David Craven <david@craven.ch>
- ;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
- ;;;
- ;;; This file is part of GNU Guix.
- ;;;
- ;;; GNU Guix is free software; you can redistribute it and/or modify it
- ;;; under the terms of the GNU General Public License as published by
- ;;; the Free Software Foundation; either version 3 of the License, or (at
- ;;; your option) any later version.
- ;;;
- ;;; GNU Guix is distributed in the hope that it will be useful, but
- ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;;; GNU General Public License for more details.
- ;;;
- ;;; You should have received a copy of the GNU General Public License
- ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
- (define-module (gnu services base)
- #:use-module (guix store)
- #:use-module (gnu services)
- #:use-module (gnu services shepherd)
- #:use-module (gnu services networking)
- #:use-module (gnu system pam)
- #:use-module (gnu system shadow) ; 'user-account', etc.
- #:use-module (gnu system uuid)
- #:use-module (gnu system file-systems) ; 'file-system', etc.
- #:use-module (gnu system mapped-devices)
- #:use-module ((gnu system linux-initrd)
- #:select (file-system-packages))
- #:use-module (gnu packages admin)
- #:use-module ((gnu packages linux)
- #:select (alsa-utils crda eudev e2fsprogs fuse gpm kbd lvm2 rng-tools))
- #:use-module ((gnu packages base)
- #:select (canonical-package glibc glibc-utf8-locales))
- #:use-module (gnu packages bash)
- #:use-module (gnu packages package-management)
- #:use-module (gnu packages linux)
- #:use-module (gnu packages lsof)
- #:use-module (gnu packages terminals)
- #:use-module ((gnu build file-systems)
- #:select (mount-flags->bit-mask))
- #:use-module (guix gexp)
- #:use-module (guix records)
- #:use-module (guix modules)
- #:use-module (srfi srfi-1)
- #:use-module (srfi srfi-26)
- #:use-module (ice-9 match)
- #:use-module (ice-9 format)
- #:export (fstab-service-type
- root-file-system-service
- file-system-service-type
- user-unmount-service
- swap-service
- user-processes-service
- host-name-service
- console-keymap-service
- %default-console-font
- console-font-service-type
- console-font-service
- udev-configuration
- udev-configuration?
- udev-configuration-rules
- udev-service-type
- udev-service
- udev-rule
- login-configuration
- login-configuration?
- login-service-type
- login-service
- agetty-configuration
- agetty-configuration?
- agetty-service
- agetty-service-type
- mingetty-configuration
- mingetty-configuration?
- mingetty-service
- mingetty-service-type
- %nscd-default-caches
- %nscd-default-configuration
- nscd-configuration
- nscd-configuration?
- nscd-cache
- nscd-cache?
- nscd-service-type
- nscd-service
- syslog-configuration
- syslog-configuration?
- syslog-service
- syslog-service-type
- %default-syslog.conf
- %default-authorized-guix-keys
- guix-configuration
- guix-configuration?
- guix-configuration-guix
- guix-configuration-build-group
- guix-configuration-build-accounts
- guix-configuration-authorize-key?
- guix-configuration-authorized-keys
- guix-configuration-use-substitutes?
- guix-configuration-substitute-urls
- guix-configuration-extra-options
- guix-configuration-log-file
- guix-configuration-lsof
- guix-service
- guix-service-type
- guix-publish-configuration
- guix-publish-configuration?
- guix-publish-configuration-guix
- guix-publish-configuration-port
- guix-publish-configuration-host
- guix-publish-configuration-compression-level
- guix-publish-configuration-nar-path
- guix-publish-configuration-cache
- guix-publish-configuration-ttl
- guix-publish-service
- guix-publish-service-type
- gpm-configuration
- gpm-configuration?
- gpm-service-type
- gpm-service
- urandom-seed-service-type
- urandom-seed-service
- rngd-configuration
- rngd-configuration?
- rngd-service-type
- rngd-service
- kmscon-configuration
- kmscon-configuration?
- kmscon-service-type
- pam-limits-service-type
- pam-limits-service
- %base-services))
- ;;; Commentary:
- ;;;
- ;;; Base system services---i.e., services that 99% of the users will want to
- ;;; use.
- ;;;
- ;;; Code:
- ;;;
- ;;; File systems.
- ;;;
- (define (file-system->fstab-entry file-system)
- "Return a @file{/etc/fstab} entry for @var{file-system}."
- (string-append (case (file-system-title file-system)
- ((label)
- (string-append "LABEL=" (file-system-device file-system)))
- ((uuid)
- (string-append
- "UUID="
- (uuid->string (file-system-device file-system))))
- (else
- (file-system-device file-system)))
- "\t"
- (file-system-mount-point file-system) "\t"
- (file-system-type file-system) "\t"
- (or (file-system-options file-system) "defaults") "\t"
- ;; XXX: Omit the 'fs_freq' and 'fs_passno' fields because we
- ;; don't have anything sensible to put in there.
- ))
- (define (file-systems->fstab file-systems)
- "Return a @file{/etc} entry for an @file{fstab} describing
- @var{file-systems}."
- `(("fstab" ,(plain-file "fstab"
- (string-append
- "\
- # This file was generated from your GuixSD configuration. Any changes
- # will be lost upon reboot or reconfiguration.\n\n"
- (string-join (map file-system->fstab-entry
- file-systems)
- "\n")
- "\n")))))
- (define fstab-service-type
- ;; The /etc/fstab service.
- (service-type (name 'fstab)
- (extensions
- (list (service-extension etc-service-type
- file-systems->fstab)))
- (compose concatenate)
- (extend append)
- (description
- "Populate the @file{/etc/fstab} based on the given file
- system objects.")))
- (define %root-file-system-shepherd-service
- (shepherd-service
- (documentation "Take care of the root file system.")
- (provision '(root-file-system))
- (start #~(const #t))
- (stop #~(lambda _
- ;; Return #f if successfully stopped.
- (sync)
- (call-with-blocked-asyncs
- (lambda ()
- (let ((null (%make-void-port "w")))
- ;; Close 'shepherd.log'.
- (display "closing log\n")
- ((@ (shepherd comm) stop-logging))
- ;; Redirect the default output ports..
- (set-current-output-port null)
- (set-current-error-port null)
- ;; Close /dev/console.
- (for-each close-fdes '(0 1 2))
- ;; At this point, there are no open files left, so the
- ;; root file system can be re-mounted read-only.
- (mount #f "/" #f
- (logior MS_REMOUNT MS_RDONLY)
- #:update-mtab? #f)
- #f)))))
- (respawn? #f)))
- (define root-file-system-service-type
- (shepherd-service-type 'root-file-system
- (const %root-file-system-shepherd-service)))
- (define (root-file-system-service)
- "Return a service whose sole purpose is to re-mount read-only the root file
- system upon shutdown (aka. cleanly \"umounting\" root.)
- This service must be the root of the service dependency graph so that its
- 'stop' action is invoked when shepherd is the only process left."
- (service root-file-system-service-type #f))
- (define (file-system->shepherd-service-name file-system)
- "Return the symbol that denotes the service mounting and unmounting
- FILE-SYSTEM."
- (symbol-append 'file-system-
- (string->symbol (file-system-mount-point file-system))))
- (define (mapped-device->shepherd-service-name md)
- "Return the symbol that denotes the shepherd service of MD, a <mapped-device>."
- (symbol-append 'device-mapping-
- (string->symbol (mapped-device-target md))))
- (define dependency->shepherd-service-name
- (match-lambda
- ((? mapped-device? md)
- (mapped-device->shepherd-service-name md))
- ((? file-system? fs)
- (file-system->shepherd-service-name fs))))
- (define (file-system-shepherd-service file-system)
- "Return the shepherd service for @var{file-system}, or @code{#f} if
- @var{file-system} is not auto-mounted upon boot."
- (let ((target (file-system-mount-point file-system))
- (create? (file-system-create-mount-point? file-system))
- (dependencies (file-system-dependencies file-system))
- (packages (file-system-packages (list file-system))))
- (and (file-system-mount? file-system)
- (with-imported-modules (source-module-closure
- '((gnu build file-systems)))
- (shepherd-service
- (provision (list (file-system->shepherd-service-name file-system)))
- (requirement `(root-file-system
- ,@(map dependency->shepherd-service-name dependencies)))
- (documentation "Check, mount, and unmount the given file system.")
- (start #~(lambda args
- #$(if create?
- #~(mkdir-p #$target)
- #t)
- (let (($PATH (getenv "PATH")))
- ;; Make sure fsck.ext2 & co. can be found.
- (dynamic-wind
- (lambda ()
- ;; Don’t display the PATH settings.
- (with-output-to-port (%make-void-port "w")
- (lambda ()
- (set-path-environment-variable "PATH"
- '("bin" "sbin")
- '#$packages))))
- (lambda ()
- (mount-file-system
- '#$(file-system->spec file-system)
- #:root "/"))
- (lambda ()
- (setenv "PATH" $PATH)))
- #t)))
- (stop #~(lambda args
- ;; Normally there are no processes left at this point, so
- ;; TARGET can be safely unmounted.
- ;; Make sure PID 1 doesn't keep TARGET busy.
- (chdir "/")
- (umount #$target)
- #f))
- ;; We need an additional module.
- (modules `(((gnu build file-systems)
- #:select (mount-file-system))
- ,@%default-modules)))))))
- (define (file-system-shepherd-services file-systems)
- "Return the list of Shepherd services for FILE-SYSTEMS."
- (let* ((file-systems (filter file-system-mount? file-systems)))
- (define sink
- (shepherd-service
- (provision '(file-systems))
- (requirement (cons* 'root-file-system 'user-file-systems
- (map file-system->shepherd-service-name
- file-systems)))
- (documentation "Target for all the initially-mounted file systems")
- (start #~(const #t))
- (stop #~(const #f))))
- (cons sink (map file-system-shepherd-service file-systems))))
- (define file-system-service-type
- (service-type (name 'file-systems)
- (extensions
- (list (service-extension shepherd-root-service-type
- file-system-shepherd-services)
- (service-extension fstab-service-type
- identity)))
- (compose concatenate)
- (extend append)
- (description
- "Provide Shepherd services to mount and unmount the given
- file systems, as well as corresponding @file{/etc/fstab} entries.")))
- (define user-unmount-service-type
- (shepherd-service-type
- 'user-file-systems
- (lambda (known-mount-points)
- (shepherd-service
- (documentation "Unmount manually-mounted file systems.")
- (provision '(user-file-systems))
- (start #~(const #t))
- (stop #~(lambda args
- (define (known? mount-point)
- (member mount-point
- (cons* "/proc" "/sys" '#$known-mount-points)))
- ;; Make sure we don't keep the user's mount points busy.
- (chdir "/")
- (for-each (lambda (mount-point)
- (format #t "unmounting '~a'...~%" mount-point)
- (catch 'system-error
- (lambda ()
- (umount mount-point))
- (lambda args
- (let ((errno (system-error-errno args)))
- (format #t "failed to unmount '~a': ~a~%"
- mount-point (strerror errno))))))
- (filter (negate known?) (mount-points)))
- #f))))))
- (define (user-unmount-service known-mount-points)
- "Return a service whose sole purpose is to unmount file systems not listed
- in KNOWN-MOUNT-POINTS when it is stopped."
- (service user-unmount-service-type known-mount-points))
- (define %do-not-kill-file
- ;; Name of the file listing PIDs of processes that must survive when halting
- ;; the system. Typical example is user-space file systems.
- "/etc/shepherd/do-not-kill")
- (define user-processes-service-type
- (shepherd-service-type
- 'user-processes
- (lambda (grace-delay)
- (shepherd-service
- (documentation "When stopped, terminate all user processes.")
- (provision '(user-processes))
- (requirement '(file-systems))
- (start #~(const #t))
- (stop #~(lambda _
- (define (kill-except omit signal)
- ;; Kill all the processes with SIGNAL except those listed
- ;; in OMIT and the current process.
- (let ((omit (cons (getpid) omit)))
- (for-each (lambda (pid)
- (unless (memv pid omit)
- (false-if-exception
- (kill pid signal))))
- (processes))))
- (define omitted-pids
- ;; List of PIDs that must not be killed.
- (if (file-exists? #$%do-not-kill-file)
- (map string->number
- (call-with-input-file #$%do-not-kill-file
- (compose string-tokenize
- (@ (ice-9 rdelim) read-string))))
- '()))
- (define (now)
- (car (gettimeofday)))
- (define (sleep* n)
- ;; Really sleep N seconds.
- ;; Work around <http://bugs.gnu.org/19581>.
- (define start (now))
- (let loop ((elapsed 0))
- (when (> n elapsed)
- (sleep (- n elapsed))
- (loop (- (now) start)))))
- (define lset= (@ (srfi srfi-1) lset=))
- (display "sending all processes the TERM signal\n")
- (if (null? omitted-pids)
- (begin
- ;; Easy: terminate all of them.
- (kill -1 SIGTERM)
- (sleep* #$grace-delay)
- (kill -1 SIGKILL))
- (begin
- ;; Kill them all except OMITTED-PIDS. XXX: We would
- ;; like to (kill -1 SIGSTOP) to get a fixed list of
- ;; processes, like 'killall5' does, but that seems
- ;; unreliable.
- (kill-except omitted-pids SIGTERM)
- (sleep* #$grace-delay)
- (kill-except omitted-pids SIGKILL)
- (delete-file #$%do-not-kill-file)))
- (let wait ()
- ;; Reap children, if any, so that we don't end up with
- ;; zombies and enter an infinite loop.
- (let reap-children ()
- (define result
- (false-if-exception
- (waitpid WAIT_ANY (if (null? omitted-pids)
- 0
- WNOHANG))))
- (when (and (pair? result)
- (not (zero? (car result))))
- (reap-children)))
- (let ((pids (processes)))
- (unless (lset= = pids (cons 1 omitted-pids))
- (format #t "waiting for process termination\
- (processes left: ~s)~%"
- pids)
- (sleep* 2)
- (wait))))
- (display "all processes have been terminated\n")
- #f))
- (respawn? #f)))))
- (define* (user-processes-service #:key (grace-delay 4))
- "Return the service that is responsible for terminating all the processes so
- that the root file system can be re-mounted read-only, just before
- rebooting/halting. Processes still running GRACE-DELAY seconds after SIGTERM
- has been sent are terminated with SIGKILL.
- The returned service will depend on 'file-systems', meaning that it is
- considered started after all the auto-mount file systems have been mounted.
- All the services that spawn processes must depend on this one so that they are
- stopped before 'kill' is called."
- (service user-processes-service-type grace-delay))
- ;;;
- ;;; Preserve entropy to seed /dev/urandom on boot.
- ;;;
- (define %random-seed-file
- "/var/lib/random-seed")
- (define (urandom-seed-shepherd-service _)
- "Return a shepherd service for the /dev/urandom seed."
- (list (shepherd-service
- (documentation "Preserve entropy across reboots for /dev/urandom.")
- (provision '(urandom-seed))
- (requirement '(user-processes))
- (start #~(lambda _
- ;; On boot, write random seed into /dev/urandom.
- (when (file-exists? #$%random-seed-file)
- (call-with-input-file #$%random-seed-file
- (lambda (seed)
- (call-with-output-file "/dev/urandom"
- (lambda (urandom)
- (dump-port seed urandom))))))
- ;; Immediately refresh the seed in case the system doesn't
- ;; shut down cleanly.
- (call-with-input-file "/dev/urandom"
- (lambda (urandom)
- (let ((previous-umask (umask #o077))
- (buf (make-bytevector 512)))
- (mkdir-p (dirname #$%random-seed-file))
- (get-bytevector-n! urandom buf 0 512)
- (call-with-output-file #$%random-seed-file
- (lambda (seed)
- (put-bytevector seed buf)))
- (umask previous-umask))))
- #t))
- (stop #~(lambda _
- ;; During shutdown, write from /dev/urandom into random seed.
- (let ((buf (make-bytevector 512)))
- (call-with-input-file "/dev/urandom"
- (lambda (urandom)
- (let ((previous-umask (umask #o077)))
- (get-bytevector-n! urandom buf 0 512)
- (mkdir-p (dirname #$%random-seed-file))
- (call-with-output-file #$%random-seed-file
- (lambda (seed)
- (put-bytevector seed buf)))
- (umask previous-umask))
- #t)))))
- (modules `((rnrs bytevectors)
- (rnrs io ports)
- ,@%default-modules)))))
- (define urandom-seed-service-type
- (service-type (name 'urandom-seed)
- (extensions
- (list (service-extension shepherd-root-service-type
- urandom-seed-shepherd-service)))
- (description
- "Seed the @file{/dev/urandom} pseudo-random number
- generator (RNG) with the value recorded when the system was last shut
- down.")))
- (define (urandom-seed-service)
- (service urandom-seed-service-type #f))
- ;;;
- ;;; Add hardware random number generator to entropy pool.
- ;;;
- (define-record-type* <rngd-configuration>
- rngd-configuration make-rngd-configuration
- rngd-configuration?
- (rng-tools rngd-configuration-rng-tools) ;package
- (device rngd-configuration-device)) ;string
- (define rngd-service-type
- (shepherd-service-type
- 'rngd
- (lambda (config)
- (define rng-tools (rngd-configuration-rng-tools config))
- (define device (rngd-configuration-device config))
- (define rngd-command
- (list (file-append rng-tools "/sbin/rngd")
- "-f" "-r" device))
- (shepherd-service
- (documentation "Add TRNG to entropy pool.")
- (requirement '(udev))
- (provision '(trng))
- (start #~(make-forkexec-constructor #$@rngd-command))
- (stop #~(make-kill-destructor))))))
- (define* (rngd-service #:key
- (rng-tools rng-tools)
- (device "/dev/hwrng"))
- "Return a service that runs the @command{rngd} program from @var{rng-tools}
- to add @var{device} to the kernel's entropy pool. The service will fail if
- @var{device} does not exist."
- (service rngd-service-type
- (rngd-configuration
- (rng-tools rng-tools)
- (device device))))
- ;;;
- ;;; Console & co.
- ;;;
- (define host-name-service-type
- (shepherd-service-type
- 'host-name
- (lambda (name)
- (shepherd-service
- (documentation "Initialize the machine's host name.")
- (provision '(host-name))
- (start #~(lambda _
- (sethostname #$name)))
- (respawn? #f)))))
- (define (host-name-service name)
- "Return a service that sets the host name to @var{name}."
- (service host-name-service-type name))
- (define (unicode-start tty)
- "Return a gexp to start Unicode support on @var{tty}."
- ;; We have to run 'unicode_start' in a pipe so that when it invokes the
- ;; 'tty' command, that command returns TTY.
- #~(begin
- (let ((pid (primitive-fork)))
- (case pid
- ((0)
- (close-fdes 0)
- (dup2 (open-fdes #$tty O_RDONLY) 0)
- (close-fdes 1)
- (dup2 (open-fdes #$tty O_WRONLY) 1)
- (execl #$(file-append kbd "/bin/unicode_start")
- "unicode_start"))
- (else
- (zero? (cdr (waitpid pid))))))))
- (define console-keymap-service-type
- (shepherd-service-type
- 'console-keymap
- (lambda (files)
- (shepherd-service
- (documentation (string-append "Load console keymap (loadkeys)."))
- (provision '(console-keymap))
- (start #~(lambda _
- (zero? (system* #$(file-append kbd "/bin/loadkeys")
- #$@files))))
- (respawn? #f)))))
- (define (console-keymap-service . files)
- "Return a service to load console keymaps from @var{files}."
- (service console-keymap-service-type files))
- (define %default-console-font
- ;; Note: 'LatGrkCyr-8x16' has the advantage of providing three common
- ;; scripts as well as glyphs for em dash, quotation marks, and other Unicode
- ;; codepoints notably found in the UTF-8 manual.
- "LatGrkCyr-8x16")
- (define (console-font-shepherd-services tty+font)
- "Return a list of Shepherd services for each pair in TTY+FONT."
- (map (match-lambda
- ((tty . font)
- (let ((device (string-append "/dev/" tty)))
- (shepherd-service
- (documentation "Load a Unicode console font.")
- (provision (list (symbol-append 'console-font-
- (string->symbol tty))))
- ;; Start after mingetty has been started on TTY, otherwise the settings
- ;; are ignored.
- (requirement (list (symbol-append 'term-
- (string->symbol tty))))
- (start #~(lambda _
- (and #$(unicode-start device)
- (zero?
- (system* #$(file-append kbd "/bin/setfont")
- "-C" #$device #$font)))))
- (stop #~(const #t))
- (respawn? #f)))))
- tty+font))
- (define console-font-service-type
- (service-type (name 'console-fonts)
- (extensions
- (list (service-extension shepherd-root-service-type
- console-font-shepherd-services)))
- (compose concatenate)
- (extend append)
- (description
- "Install the given fonts on the specified ttys (fonts are per
- virtual console on GNU/Linux). The value of this service is a list of
- tty/font pairs like:
- @example
- '((\"tty1\" . \"LatGrkCyr-8x16\"))
- @end example\n")))
- (define* (console-font-service tty #:optional (font "LatGrkCyr-8x16"))
- "This procedure is deprecated in favor of @code{console-font-service-type}.
- Return a service that sets up Unicode support in @var{tty} and loads
- @var{font} for that tty (fonts are per virtual console in Linux.)"
- (simple-service (symbol-append 'console-font- (string->symbol tty))
- console-font-service-type `((,tty . ,font))))
- (define %default-motd
- (plain-file "motd" "This is the GNU operating system, welcome!\n\n"))
- (define-record-type* <login-configuration>
- login-configuration make-login-configuration
- login-configuration?
- (motd login-configuration-motd ;file-like
- (default %default-motd))
- ;; Allow empty passwords by default so that first-time users can log in when
- ;; the 'root' account has just been created.
- (allow-empty-passwords? login-configuration-allow-empty-passwords?
- (default #t))) ;Boolean
- (define (login-pam-service config)
- "Return the list of PAM service needed for CONF."
- ;; Let 'login' be known to PAM.
- (list (unix-pam-service "login"
- #:allow-empty-passwords?
- (login-configuration-allow-empty-passwords? config)
- #:motd
- (login-configuration-motd config))))
- (define login-service-type
- (service-type (name 'login)
- (extensions (list (service-extension pam-root-service-type
- login-pam-service)))
- (description
- "Provide a console log-in service as specified by its
- configuration value, a @code{login-configuration} object.")))
- (define* (login-service #:optional (config (login-configuration)))
- "Return a service configure login according to @var{config}, which specifies
- the message of the day, among other things."
- (service login-service-type config))
- (define-record-type* <agetty-configuration>
- agetty-configuration make-agetty-configuration
- agetty-configuration?
- (agetty agetty-configuration-agetty ;<package>
- (default util-linux))
- (tty agetty-configuration-tty) ;string
- (term agetty-term ;string | #f
- (default #f))
- (baud-rate agetty-baud-rate ;string | #f
- (default #f))
- (auto-login agetty-auto-login ;list of strings | #f
- (default #f))
- (login-program agetty-login-program ;gexp
- (default (file-append shadow "/bin/login")))
- (login-pause? agetty-login-pause? ;Boolean
- (default #f))
- (eight-bits? agetty-eight-bits? ;Boolean
- (default #f))
- (no-reset? agetty-no-reset? ;Boolean
- (default #f))
- (remote? agetty-remote? ;Boolean
- (default #f))
- (flow-control? agetty-flow-control? ;Boolean
- (default #f))
- (host agetty-host ;string | #f
- (default #f))
- (no-issue? agetty-no-issue? ;Boolean
- (default #f))
- (init-string agetty-init-string ;string | #f
- (default #f))
- (no-clear? agetty-no-clear? ;Boolean
- (default #f))
- (local-line agetty-local-line ;always | never | auto
- (default #f))
- (extract-baud? agetty-extract-baud? ;Boolean
- (default #f))
- (skip-login? agetty-skip-login? ;Boolean
- (default #f))
- (no-newline? agetty-no-newline? ;Boolean
- (default #f))
- (login-options agetty-login-options ;string | #f
- (default #f))
- (chroot agetty-chroot ;string | #f
- (default #f))
- (hangup? agetty-hangup? ;Boolean
- (default #f))
- (keep-baud? agetty-keep-baud? ;Boolean
- (default #f))
- (timeout agetty-timeout ;integer | #f
- (default #f))
- (detect-case? agetty-detect-case? ;Boolean
- (default #f))
- (wait-cr? agetty-wait-cr? ;Boolean
- (default #f))
- (no-hints? agetty-no-hints? ;Boolean
- (default #f))
- (no-hostname? agetty-no hostname? ;Boolean
- (default #f))
- (long-hostname? agetty-long-hostname? ;Boolean
- (default #f))
- (erase-characters agetty-erase-characters ;string | #f
- (default #f))
- (kill-characters agetty-kill-characters ;string | #f
- (default #f))
- (chdir agetty-chdir ;string | #f
- (default #f))
- (delay agetty-delay ;integer | #f
- (default #f))
- (nice agetty-nice ;integer | #f
- (default #f))
- ;; "Escape hatch" for passing arbitrary command-line arguments.
- (extra-options agetty-extra-options ;list of strings
- (default '()))
- ;;; XXX Unimplemented for now!
- ;;; (issue-file agetty-issue-file ;file-like
- ;;; (default #f))
- )
- (define agetty-shepherd-service
- (match-lambda
- (($ <agetty-configuration> agetty tty term baud-rate auto-login
- login-program login-pause? eight-bits? no-reset? remote? flow-control?
- host no-issue? init-string no-clear? local-line extract-baud?
- skip-login? no-newline? login-options chroot hangup? keep-baud? timeout
- detect-case? wait-cr? no-hints? no-hostname? long-hostname?
- erase-characters kill-characters chdir delay nice extra-options)
- (list
- (shepherd-service
- (documentation "Run agetty on a tty.")
- (provision (list (symbol-append 'term- (string->symbol tty))))
- ;; Since the login prompt shows the host name, wait for the 'host-name'
- ;; service to be done. Also wait for udev essentially so that the tty
- ;; text is not lost in the middle of kernel messages (see also
- ;; mingetty-shepherd-service).
- (requirement '(user-processes host-name udev))
- (start #~(make-forkexec-constructor
- (list #$(file-append util-linux "/sbin/agetty")
- #$@extra-options
- #$@(if eight-bits?
- #~("--8bits")
- #~())
- #$@(if no-reset?
- #~("--noreset")
- #~())
- #$@(if remote?
- #~("--remote")
- #~())
- #$@(if flow-control?
- #~("--flow-control")
- #~())
- #$@(if host
- #~("--host" #$host)
- #~())
- #$@(if no-issue?
- #~("--noissue")
- #~())
- #$@(if init-string
- #~("--init-string" #$init-string)
- #~())
- #$@(if no-clear?
- #~("--noclear")
- #~())
- ;;; FIXME This doesn't work as expected. According to agetty(8), if this option
- ;;; is not passed, then the default is 'auto'. However, in my tests, when that
- ;;; option is selected, agetty never presents the login prompt, and the
- ;;; term-ttyS0 service respawns every few seconds.
- #$@(if local-line
- #~(#$(match local-line
- ('auto "--local-line=auto")
- ('always "--local-line=always")
- ('never "-local-line=never")))
- #~())
- #$@(if extract-baud?
- #~("--extract-baud")
- #~())
- #$@(if skip-login?
- #~("--skip-login")
- #~())
- #$@(if no-newline?
- #~("--nonewline")
- #~())
- #$@(if login-options
- #~("--login-options" #$login-options)
- #~())
- #$@(if chroot
- #~("--chroot" #$chroot)
- #~())
- #$@(if hangup?
- #~("--hangup")
- #~())
- #$@(if keep-baud?
- #~("--keep-baud")
- #~())
- #$@(if timeout
- #~("--timeout" #$(number->string timeout))
- #~())
- #$@(if detect-case?
- #~("--detect-case")
- #~())
- #$@(if wait-cr?
- #~("--wait-cr")
- #~())
- #$@(if no-hints?
- #~("--nohints?")
- #~())
- #$@(if no-hostname?
- #~("--nohostname")
- #~())
- #$@(if long-hostname?
- #~("--long-hostname")
- #~())
- #$@(if erase-characters
- #~("--erase-chars" #$erase-characters)
- #~())
- #$@(if kill-characters
- #~("--kill-chars" #$kill-characters)
- #~())
- #$@(if chdir
- #~("--chdir" #$chdir)
- #~())
- #$@(if delay
- #~("--delay" #$(number->string delay))
- #~())
- #$@(if nice
- #~("--nice" #$(number->string nice))
- #~())
- #$@(if auto-login
- (list "--autologin" auto-login)
- '())
- #$@(if login-program
- #~("--login-program" #$login-program)
- #~())
- #$@(if login-pause?
- #~("--login-pause")
- #~())
- #$tty
- #$@(if baud-rate
- #~(#$baud-rate)
- #~())
- #$@(if term
- #~(#$term)
- #~()))))
- (stop #~(make-kill-destructor)))))))
- (define agetty-service-type
- (service-type (name 'agetty)
- (extensions (list (service-extension shepherd-root-service-type
- agetty-shepherd-service)))
- (description
- "Provide console login using the @command{agetty}
- program.")))
- (define* (agetty-service config)
- "Return a service to run agetty according to @var{config}, which specifies
- the tty to run, among other things."
- (service agetty-service-type config))
- (define-record-type* <mingetty-configuration>
- mingetty-configuration make-mingetty-configuration
- mingetty-configuration?
- (mingetty mingetty-configuration-mingetty ;<package>
- (default mingetty))
- (tty mingetty-configuration-tty) ;string
- (auto-login mingetty-auto-login ;string | #f
- (default #f))
- (login-program mingetty-login-program ;gexp
- (default #f))
- (login-pause? mingetty-login-pause? ;Boolean
- (default #f)))
- (define mingetty-shepherd-service
- (match-lambda
- (($ <mingetty-configuration> mingetty tty auto-login login-program
- login-pause?)
- (list
- (shepherd-service
- (documentation "Run mingetty on an tty.")
- (provision (list (symbol-append 'term- (string->symbol tty))))
- ;; Since the login prompt shows the host name, wait for the 'host-name'
- ;; service to be done. Also wait for udev essentially so that the tty
- ;; text is not lost in the middle of kernel messages (XXX).
- (requirement '(user-processes host-name udev))
- (start #~(make-forkexec-constructor
- (list #$(file-append mingetty "/sbin/mingetty")
- "--noclear" #$tty
- #$@(if auto-login
- #~("--autologin" #$auto-login)
- #~())
- #$@(if login-program
- #~("--loginprog" #$login-program)
- #~())
- #$@(if login-pause?
- #~("--loginpause")
- #~()))))
- (stop #~(make-kill-destructor)))))))
- (define mingetty-service-type
- (service-type (name 'mingetty)
- (extensions (list (service-extension shepherd-root-service-type
- mingetty-shepherd-service)))
- (description
- "Provide console login using the @command{mingetty}
- program.")))
- (define* (mingetty-service config)
- "Return a service to run mingetty according to @var{config}, which specifies
- the tty to run, among other things."
- (service mingetty-service-type config))
- (define-record-type* <nscd-configuration> nscd-configuration
- make-nscd-configuration
- nscd-configuration?
- (log-file nscd-configuration-log-file ;string
- (default "/var/log/nscd.log"))
- (debug-level nscd-debug-level ;integer
- (default 0))
- ;; TODO: See nscd.conf in glibc for other options to add.
- (caches nscd-configuration-caches ;list of <nscd-cache>
- (default %nscd-default-caches))
- (name-services nscd-configuration-name-services ;list of <packages>
- (default '()))
- (glibc nscd-configuration-glibc ;<package>
- (default (canonical-package glibc))))
- (define-record-type* <nscd-cache> nscd-cache make-nscd-cache
- nscd-cache?
- (database nscd-cache-database) ;symbol
- (positive-time-to-live nscd-cache-positive-time-to-live) ;integer
- (negative-time-to-live nscd-cache-negative-time-to-live
- (default 20)) ;integer
- (suggested-size nscd-cache-suggested-size ;integer ("default module
- ;of hash table")
- (default 211))
- (check-files? nscd-cache-check-files? ;Boolean
- (default #t))
- (persistent? nscd-cache-persistent? ;Boolean
- (default #t))
- (shared? nscd-cache-shared? ;Boolean
- (default #t))
- (max-database-size nscd-cache-max-database-size ;integer
- (default (* 32 (expt 2 20))))
- (auto-propagate? nscd-cache-auto-propagate? ;Boolean
- (default #t)))
- (define %nscd-default-caches
- ;; Caches that we want to enable by default. Note that when providing an
- ;; empty nscd.conf, all caches are disabled.
- (list (nscd-cache (database 'hosts)
- ;; Aggressively cache the host name cache to improve
- ;; privacy and resilience.
- (positive-time-to-live (* 3600 12))
- (negative-time-to-live 20)
- (persistent? #t))
- (nscd-cache (database 'services)
- ;; Services are unlikely to change, so we can be even more
- ;; aggressive.
- (positive-time-to-live (* 3600 24))
- (negative-time-to-live 3600)
- (check-files? #t) ;check /etc/services changes
- (persistent? #t))))
- (define %nscd-default-configuration
- ;; Default nscd configuration.
- (nscd-configuration))
- (define (nscd.conf-file config)
- "Return the @file{nscd.conf} configuration file for @var{config}, an
- @code{<nscd-configuration>} object."
- (define cache->config
- (match-lambda
- (($ <nscd-cache> (= symbol->string database)
- positive-ttl negative-ttl size check-files?
- persistent? shared? max-size propagate?)
- (string-append "\nenable-cache\t" database "\tyes\n"
- "positive-time-to-live\t" database "\t"
- (number->string positive-ttl) "\n"
- "negative-time-to-live\t" database "\t"
- (number->string negative-ttl) "\n"
- "suggested-size\t" database "\t"
- (number->string size) "\n"
- "check-files\t" database "\t"
- (if check-files? "yes\n" "no\n")
- "persistent\t" database "\t"
- (if persistent? "yes\n" "no\n")
- "shared\t" database "\t"
- (if shared? "yes\n" "no\n")
- "max-db-size\t" database "\t"
- (number->string max-size) "\n"
- "auto-propagate\t" database "\t"
- (if propagate? "yes\n" "no\n")))))
- (match config
- (($ <nscd-configuration> log-file debug-level caches)
- (plain-file "nscd.conf"
- (string-append "\
- # Configuration of libc's name service cache daemon (nscd).\n\n"
- (if log-file
- (string-append "logfile\t" log-file)
- "")
- "\n"
- (if debug-level
- (string-append "debug-level\t"
- (number->string debug-level))
- "")
- "\n"
- (string-concatenate
- (map cache->config caches)))))))
- (define (nscd-shepherd-service config)
- "Return a shepherd service for CONFIG, an <nscd-configuration> object."
- (let ((nscd.conf (nscd.conf-file config))
- (name-services (nscd-configuration-name-services config)))
- (list (shepherd-service
- (documentation "Run libc's name service cache daemon (nscd).")
- (provision '(nscd))
- (requirement '(user-processes))
- (start #~(make-forkexec-constructor
- (list #$(file-append (nscd-configuration-glibc config)
- "/sbin/nscd")
- "-f" #$nscd.conf "--foreground")
- ;; Wait for the PID file. However, the PID file is
- ;; written before nscd is actually listening on its
- ;; socket (XXX).
- #:pid-file "/var/run/nscd/nscd.pid"
- #:environment-variables
- (list (string-append "LD_LIBRARY_PATH="
- (string-join
- (map (lambda (dir)
- (string-append dir "/lib"))
- (list #$@name-services))
- ":")))))
- (stop #~(make-kill-destructor))))))
- (define nscd-activation
- ;; Actions to take before starting nscd.
- #~(begin
- (use-modules (guix build utils))
- (mkdir-p "/var/run/nscd")
- (mkdir-p "/var/db/nscd") ;for the persistent cache
- ;; In libc 2.25 nscd uses inotify to watch /etc/resolv.conf, but only if
- ;; that file exists when it is started. Thus create it here. Note: on
- ;; some systems, such as when NetworkManager is used, /etc/resolv.conf
- ;; is a symlink, hence 'lstat'.
- (unless (false-if-exception (lstat "/etc/resolv.conf"))
- (call-with-output-file "/etc/resolv.conf"
- (lambda (port)
- (display "# This is a placeholder.\n" port))))))
- (define nscd-service-type
- (service-type (name 'nscd)
- (extensions
- (list (service-extension activation-service-type
- (const nscd-activation))
- (service-extension shepherd-root-service-type
- nscd-shepherd-service)))
- ;; This can be extended by providing additional name services
- ;; such as nss-mdns.
- (compose concatenate)
- (extend (lambda (config name-services)
- (nscd-configuration
- (inherit config)
- (name-services (append
- (nscd-configuration-name-services config)
- name-services)))))
- (description
- "Runs libc's @dfn{name service cache daemon} (nscd) with the
- given configuration---an @code{<nscd-configuration>} object. @xref{Name
- Service Switch}, for an example.")))
- (define* (nscd-service #:optional (config %nscd-default-configuration))
- "Return a service that runs libc's name service cache daemon (nscd) with the
- given @var{config}---an @code{<nscd-configuration>} object. @xref{Name
- Service Switch}, for an example."
- (service nscd-service-type config))
- (define-record-type* <syslog-configuration>
- syslog-configuration make-syslog-configuration
- syslog-configuration?
- (syslogd syslog-configuration-syslogd
- (default (file-append inetutils "/libexec/syslogd")))
- (config-file syslog-configuration-config-file
- (default %default-syslog.conf)))
- (define syslog-service-type
- (shepherd-service-type
- 'syslog
- (lambda (config)
- (shepherd-service
- (documentation "Run the syslog daemon (syslogd).")
- (provision '(syslogd))
- (requirement '(user-processes))
- (start #~(make-forkexec-constructor
- (list #$(syslog-configuration-syslogd config)
- "--rcfile" #$(syslog-configuration-config-file config))
- #:pid-file "/var/run/syslog.pid"))
- (stop #~(make-kill-destructor))))))
- ;; Snippet adapted from the GNU inetutils manual.
- (define %default-syslog.conf
- (plain-file "syslog.conf" "
- # Log all error messages, authentication messages of
- # level notice or higher and anything of level err or
- # higher to the console.
- # Don't log private authentication messages!
- *.alert;auth.notice;authpriv.none /dev/console
- # Log anything (except mail) of level info or higher.
- # Don't log private authentication messages!
- *.info;mail.none;authpriv.none /var/log/messages
- # Like /var/log/messages, but also including \"debug\"-level logs.
- *.debug;mail.none;authpriv.none /var/log/debug
- # Same, in a different place.
- *.info;mail.none;authpriv.none /dev/tty12
- # The authpriv file has restricted access.
- authpriv.* /var/log/secure
- # Log all the mail messages in one place.
- mail.* /var/log/maillog
- "))
- (define* (syslog-service #:optional (config (syslog-configuration)))
- "Return a service that runs @command{syslogd} and takes
- @var{<syslog-configuration>} as a parameter.
- @xref{syslogd invocation,,, inetutils, GNU Inetutils}, for more
- information on the configuration file syntax."
- (service syslog-service-type config))
- (define pam-limits-service-type
- (let ((security-limits
- ;; Create /etc/security containing the provided "limits.conf" file.
- (lambda (limits-file)
- `(("security"
- ,(computed-file
- "security"
- #~(begin
- (mkdir #$output)
- (stat #$limits-file)
- (symlink #$limits-file
- (string-append #$output "/limits.conf"))))))))
- (pam-extension
- (lambda (pam)
- (let ((pam-limits (pam-entry
- (control "required")
- (module "pam_limits.so")
- (arguments '("conf=/etc/security/limits.conf")))))
- (if (member (pam-service-name pam)
- '("login" "su" "slim"))
- (pam-service
- (inherit pam)
- (session (cons pam-limits
- (pam-service-session pam))))
- pam)))))
- (service-type
- (name 'limits)
- (extensions
- (list (service-extension etc-service-type security-limits)
- (service-extension pam-root-service-type
- (lambda _ (list pam-extension)))))
- (description
- "Install the specified resource usage limits by populating
- @file{/etc/security/limits.conf} and using the @code{pam_limits}
- authentication module."))))
- (define* (pam-limits-service #:optional (limits '()))
- "Return a service that makes selected programs respect the list of
- pam-limits-entry specified in LIMITS via pam_limits.so."
- (service pam-limits-service-type
- (plain-file "limits.conf"
- (string-join (map pam-limits-entry->string limits)
- "\n"))))
- ;;;
- ;;; Guix services.
- ;;;
- (define* (guix-build-accounts count #:key
- (group "guixbuild")
- (first-uid 30001)
- (shadow shadow))
- "Return a list of COUNT user accounts for Guix build users, with UIDs
- starting at FIRST-UID, and under GID."
- (unfold (cut > <> count)
- (lambda (n)
- (user-account
- (name (format #f "guixbuilder~2,'0d" n))
- (system? #t)
- (uid (+ first-uid n -1))
- (group group)
- ;; guix-daemon expects GROUP to be listed as a
- ;; supplementary group too:
- ;; <http://lists.gnu.org/archive/html/bug-guix/2013-01/msg00239.html>.
- (supplementary-groups (list group "kvm"))
- (comment (format #f "Guix Build User ~2d" n))
- (home-directory "/var/empty")
- (shell (file-append shadow "/sbin/nologin"))))
- 1+
- 1))
- (define (hydra-key-authorization key guix)
- "Return a gexp with code to register KEY, a file containing a 'guix archive'
- public key, with GUIX."
- #~(unless (file-exists? "/etc/guix/acl")
- (let ((pid (primitive-fork)))
- (case pid
- ((0)
- (let* ((key #$key)
- (port (open-file key "r0b")))
- (format #t "registering public key '~a'...~%" key)
- (close-port (current-input-port))
- (dup port 0)
- (execl #$(file-append guix "/bin/guix")
- "guix" "archive" "--authorize")
- (exit 1)))
- (else
- (let ((status (cdr (waitpid pid))))
- (unless (zero? status)
- (format (current-error-port) "warning: \
- failed to register hydra.gnu.org public key: ~a~%" status))))))))
- (define %default-authorized-guix-keys
- ;; List of authorized substitute keys.
- (list (file-append guix "/share/guix/hydra.gnu.org.pub")
- (file-append guix "/share/guix/bayfront.guixsd.org.pub")))
- (define-record-type* <guix-configuration>
- guix-configuration make-guix-configuration
- guix-configuration?
- (guix guix-configuration-guix ;<package>
- (default guix))
- (build-group guix-configuration-build-group ;string
- (default "guixbuild"))
- (build-accounts guix-configuration-build-accounts ;integer
- (default 10))
- (authorize-key? guix-configuration-authorize-key? ;Boolean
- (default #t))
- (authorized-keys guix-configuration-authorized-keys ;list of gexps
- (default %default-authorized-guix-keys))
- (use-substitutes? guix-configuration-use-substitutes? ;Boolean
- (default #t))
- (substitute-urls guix-configuration-substitute-urls ;list of strings
- (default %default-substitute-urls))
- (max-silent-time guix-configuration-max-silent-time ;integer
- (default 0))
- (timeout guix-configuration-timeout ;integer
- (default 0))
- (extra-options guix-configuration-extra-options ;list of strings
- (default '()))
- (log-file guix-configuration-log-file ;string
- (default "/var/log/guix-daemon.log"))
- (lsof guix-configuration-lsof ;<package>
- (default lsof))
- (http-proxy guix-http-proxy ;string | #f
- (default #f))
- (tmpdir guix-tmpdir ;string | #f
- (default #f)))
- (define %default-guix-configuration
- (guix-configuration))
- (define (guix-shepherd-service config)
- "Return a <shepherd-service> for the Guix daemon service with CONFIG."
- (match config
- (($ <guix-configuration> guix build-group build-accounts
- authorize-key? keys
- use-substitutes? substitute-urls
- max-silent-time timeout
- extra-options
- log-file lsof http-proxy tmpdir)
- (list (shepherd-service
- (documentation "Run the Guix daemon.")
- (provision '(guix-daemon))
- (requirement '(user-processes))
- (start
- #~(make-forkexec-constructor
- (list #$(file-append guix "/bin/guix-daemon")
- "--build-users-group" #$build-group
- "--max-silent-time" #$(number->string max-silent-time)
- "--timeout" #$(number->string timeout)
- #$@(if use-substitutes?
- '()
- '("--no-substitutes"))
- "--substitute-urls" #$(string-join substitute-urls)
- #$@extra-options)
- ;; Add 'lsof' (for the GC) to the daemon's $PATH.
- #:environment-variables
- (list (string-append "PATH=" #$lsof "/bin")
- #$@(if http-proxy
- (list (string-append "http_proxy=" http-proxy))
- '())
- #$@(if tmpdir
- (list (string-append "TMPDIR=" tmpdir))
- '()))
- #:log-file #$log-file))
- (stop #~(make-kill-destructor)))))))
- (define (guix-accounts config)
- "Return the user accounts and user groups for CONFIG."
- (match config
- (($ <guix-configuration> _ build-group build-accounts)
- (cons (user-group
- (name build-group)
- (system? #t)
- ;; Use a fixed GID so that we can create the store with the right
- ;; owner.
- (id 30000))
- (guix-build-accounts build-accounts
- #:group build-group)))))
- (define (guix-activation config)
- "Return the activation gexp for CONFIG."
- (match config
- (($ <guix-configuration> guix build-group build-accounts authorize-key? keys)
- ;; Assume that the store has BUILD-GROUP as its group. We could
- ;; otherwise call 'chown' here, but the problem is that on a COW unionfs,
- ;; chown leads to an entire copy of the tree, which is a bad idea.
- ;; Optionally authorize hydra.gnu.org's key.
- (if authorize-key?
- #~(begin
- #$@(map (cut hydra-key-authorization <> guix) keys))
- #~#f))))
- (define guix-service-type
- (service-type
- (name 'guix)
- (extensions
- (list (service-extension shepherd-root-service-type guix-shepherd-service)
- (service-extension account-service-type guix-accounts)
- (service-extension activation-service-type guix-activation)
- (service-extension profile-service-type
- (compose list guix-configuration-guix))))
- (default-value (guix-configuration))
- (description
- "Run the build daemon of GNU@tie{}Guix, aka. @command{guix-daemon}.")))
- (define* (guix-service #:optional (config %default-guix-configuration))
- "Return a service that runs the Guix build daemon according to
- @var{config}."
- (service guix-service-type config))
- (define-record-type* <guix-publish-configuration>
- guix-publish-configuration make-guix-publish-configuration
- guix-publish-configuration?
- (guix guix-publish-configuration-guix ;package
- (default guix))
- (port guix-publish-configuration-port ;number
- (default 80))
- (host guix-publish-configuration-host ;string
- (default "localhost"))
- (compression-level guix-publish-configuration-compression-level ;integer
- (default 3))
- (nar-path guix-publish-configuration-nar-path ;string
- (default "nar"))
- (cache guix-publish-configuration-cache ;#f | string
- (default #f))
- (workers guix-publish-configuration-workers ;#f | integer
- (default #f))
- (ttl guix-publish-configuration-ttl ;#f | integer
- (default #f)))
- (define guix-publish-shepherd-service
- (match-lambda
- (($ <guix-publish-configuration> guix port host compression
- nar-path cache workers ttl)
- (list (shepherd-service
- (provision '(guix-publish))
- (requirement '(guix-daemon))
- (start #~(make-forkexec-constructor
- (list #$(file-append guix "/bin/guix")
- "publish" "-u" "guix-publish"
- "-p" #$(number->string port)
- "-C" #$(number->string compression)
- (string-append "--nar-path=" #$nar-path)
- (string-append "--listen=" #$host)
- #$@(if workers
- #~((string-append "--workers="
- #$(number->string
- workers)))
- #~())
- #$@(if ttl
- #~((string-append "--ttl="
- #$(number->string ttl)
- "s"))
- #~())
- #$@(if cache
- #~((string-append "--cache=" #$cache))
- #~()))
- ;; Make sure we run in a UTF-8 locale so we can produce
- ;; nars for packages that contain UTF-8 file names such
- ;; as 'nss-certs'. See <https://bugs.gnu.org/26948>.
- #:environment-variables
- (list (string-append "GUIX_LOCPATH="
- #$glibc-utf8-locales "/lib/locale")
- "LC_ALL=en_US.utf8")))
- (stop #~(make-kill-destructor)))))))
- (define %guix-publish-accounts
- (list (user-group (name "guix-publish") (system? #t))
- (user-account
- (name "guix-publish")
- (group "guix-publish")
- (system? #t)
- (comment "guix publish user")
- (home-directory "/var/empty")
- (shell (file-append shadow "/sbin/nologin")))))
- (define (guix-publish-activation config)
- (let ((cache (guix-publish-configuration-cache config)))
- (if cache
- (with-imported-modules '((guix build utils))
- #~(begin
- (use-modules (guix build utils))
- (mkdir-p #$cache)
- (let* ((pw (getpw "guix-publish"))
- (uid (passwd:uid pw))
- (gid (passwd:gid pw)))
- (chown #$cache uid gid))))
- #t)))
- (define guix-publish-service-type
- (service-type (name 'guix-publish)
- (extensions
- (list (service-extension shepherd-root-service-type
- guix-publish-shepherd-service)
- (service-extension account-service-type
- (const %guix-publish-accounts))
- (service-extension activation-service-type
- guix-publish-activation)))
- (default-value (guix-publish-configuration))
- (description
- "Add a Shepherd service running @command{guix publish}, a
- command that allows you to share pre-built binaries with others over HTTP.")))
- (define* (guix-publish-service #:key (guix guix) (port 80) (host "localhost"))
- "Return a service that runs @command{guix publish} listening on @var{host}
- and @var{port} (@pxref{Invoking guix publish}).
- This assumes that @file{/etc/guix} already contains a signing key pair as
- created by @command{guix archive --generate-key} (@pxref{Invoking guix
- archive}). If that is not the case, the service will fail to start."
- ;; Deprecated.
- (service guix-publish-service-type
- (guix-publish-configuration (guix guix) (port port) (host host))))
- ;;;
- ;;; Udev.
- ;;;
- (define-record-type* <udev-configuration>
- udev-configuration make-udev-configuration
- udev-configuration?
- (udev udev-configuration-udev ;<package>
- (default udev))
- (rules udev-configuration-rules ;list of <package>
- (default '())))
- (define (udev-rules-union packages)
- "Return the union of the @code{lib/udev/rules.d} directories found in each
- item of @var{packages}."
- (define build
- (with-imported-modules '((guix build union)
- (guix build utils))
- #~(begin
- (use-modules (guix build union)
- (guix build utils)
- (srfi srfi-1)
- (srfi srfi-26))
- (define %standard-locations
- '("/lib/udev/rules.d" "/libexec/udev/rules.d"))
- (define (rules-sub-directory directory)
- ;; Return the sub-directory of DIRECTORY containing udev rules, or
- ;; #f if none was found.
- (find directory-exists?
- (map (cut string-append directory <>) %standard-locations)))
- (mkdir-p (string-append #$output "/lib/udev"))
- (union-build (string-append #$output "/lib/udev/rules.d")
- (filter-map rules-sub-directory '#$packages)))))
- (computed-file "udev-rules" build))
- (define (udev-rule file-name contents)
- "Return a directory with a udev rule file FILE-NAME containing CONTENTS."
- (computed-file file-name
- (with-imported-modules '((guix build utils))
- #~(begin
- (use-modules (guix build utils))
- (define rules.d
- (string-append #$output "/lib/udev/rules.d"))
- (mkdir-p rules.d)
- (call-with-output-file
- (string-append rules.d "/" #$file-name)
- (lambda (port)
- (display #$contents port)))))))
- (define kvm-udev-rule
- ;; Return a directory with a udev rule that changes the group of /dev/kvm to
- ;; "kvm" and makes it #o660. Apparently QEMU-KVM used to ship this rule,
- ;; but now we have to add it by ourselves.
- ;; Build users are part of the "kvm" group, so we can fearlessly make
- ;; /dev/kvm 660 (see <http://bugs.gnu.org/18994>, for background.)
- (udev-rule "90-kvm.rules"
- "KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0660\"\n"))
- (define udev-shepherd-service
- ;; Return a <shepherd-service> for UDEV with RULES.
- (match-lambda
- (($ <udev-configuration> udev rules)
- (let* ((rules (udev-rules-union (cons* udev kvm-udev-rule rules)))
- (udev.conf (computed-file "udev.conf"
- #~(call-with-output-file #$output
- (lambda (port)
- (format port
- "udev_rules=\"~a/lib/udev/rules.d\"\n"
- #$rules))))))
- (list
- (shepherd-service
- (provision '(udev))
- ;; Udev needs /dev to be a 'devtmpfs' mount so that new device nodes can
- ;; be added: see
- ;; <http://www.linuxfromscratch.org/lfs/view/development/chapter07/udev.html>.
- (requirement '(root-file-system))
- (documentation "Populate the /dev directory, dynamically.")
- (start #~(lambda ()
- (define find
- (@ (srfi srfi-1) find))
- (define udevd
- ;; Choose the right 'udevd'.
- (find file-exists?
- (map (lambda (suffix)
- (string-append #$udev suffix))
- '("/libexec/udev/udevd" ;udev
- "/sbin/udevd")))) ;eudev
- (define (wait-for-udevd)
- ;; Wait until someone's listening on udevd's control
- ;; socket.
- (let ((sock (socket AF_UNIX SOCK_SEQPACKET 0)))
- (let try ()
- (catch 'system-error
- (lambda ()
- (connect sock PF_UNIX "/run/udev/control")
- (close-port sock))
- (lambda args
- (format #t "waiting for udevd...~%")
- (usleep 500000)
- (try))))))
- ;; Allow udev to find the modules.
- (setenv "LINUX_MODULE_DIRECTORY"
- "/run/booted-system/kernel/lib/modules")
- ;; The first one is for udev, the second one for eudev.
- (setenv "UDEV_CONFIG_FILE" #$udev.conf)
- (setenv "EUDEV_RULES_DIRECTORY"
- #$(file-append rules "/lib/udev/rules.d"))
- (let ((pid (primitive-fork)))
- (case pid
- ((0)
- (exec-command (list udevd)))
- (else
- ;; Wait until udevd is up and running. This
- ;; appears to be needed so that the events
- ;; triggered below are actually handled.
- (wait-for-udevd)
- ;; Trigger device node creation.
- (system* #$(file-append udev "/bin/udevadm")
- "trigger" "--action=add")
- ;; Wait for things to settle down.
- (system* #$(file-append udev "/bin/udevadm")
- "settle")
- pid)))))
- (stop #~(make-kill-destructor))
- ;; When halting the system, 'udev' is actually killed by
- ;; 'user-processes', i.e., before its own 'stop' method was called.
- ;; Thus, make sure it is not respawned.
- (respawn? #f)))))))
- (define udev-service-type
- (service-type (name 'udev)
- (extensions
- (list (service-extension shepherd-root-service-type
- udev-shepherd-service)))
- (compose concatenate) ;concatenate the list of rules
- (extend (lambda (config rules)
- (match config
- (($ <udev-configuration> udev initial-rules)
- (udev-configuration
- (udev udev)
- (rules (append initial-rules rules)))))))
- (description
- "Run @command{udev}, which populates the @file{/dev}
- directory dynamically. Get extra rules from the packages listed in the
- @code{rules} field of its value, @code{udev-configuration} object.")))
- (define* (udev-service #:key (udev eudev) (rules '()))
- "Run @var{udev}, which populates the @file{/dev} directory dynamically. Get
- extra rules from the packages listed in @var{rules}."
- (service udev-service-type
- (udev-configuration (udev udev) (rules rules))))
- (define swap-service-type
- (shepherd-service-type
- 'swap
- (lambda (device)
- (define requirement
- (if (string-prefix? "/dev/mapper/" device)
- (list (symbol-append 'device-mapping-
- (string->symbol (basename device))))
- '()))
- (shepherd-service
- (provision (list (symbol-append 'swap- (string->symbol device))))
- (requirement `(udev ,@requirement))
- (documentation "Enable the given swap device.")
- (start #~(lambda ()
- (restart-on-EINTR (swapon #$device))
- #t))
- (stop #~(lambda _
- (restart-on-EINTR (swapoff #$device))
- #f))
- (respawn? #f)))))
- (define (swap-service device)
- "Return a service that uses @var{device} as a swap device."
- (service swap-service-type device))
- (define-record-type* <gpm-configuration>
- gpm-configuration make-gpm-configuration gpm-configuration?
- (gpm gpm-configuration-gpm) ;package
- (options gpm-configuration-options)) ;list of strings
- (define gpm-shepherd-service
- (match-lambda
- (($ <gpm-configuration> gpm options)
- (list (shepherd-service
- (requirement '(udev))
- (provision '(gpm))
- (start #~(lambda ()
- ;; 'gpm' runs in the background and sets a PID file.
- ;; Note that it requires running as "root".
- (false-if-exception (delete-file "/var/run/gpm.pid"))
- (fork+exec-command (list #$(file-append gpm "/sbin/gpm")
- #$@options))
- ;; Wait for the PID file to appear; declare failure if
- ;; it doesn't show up.
- (let loop ((i 3))
- (or (file-exists? "/var/run/gpm.pid")
- (if (zero? i)
- #f
- (begin
- (sleep 1)
- (loop (1- i))))))))
- (stop #~(lambda (_)
- ;; Return #f if successfully stopped.
- (not (zero? (system* #$(file-append gpm "/sbin/gpm")
- "-k"))))))))))
- (define gpm-service-type
- (service-type (name 'gpm)
- (extensions
- (list (service-extension shepherd-root-service-type
- gpm-shepherd-service)))
- (description
- "Run GPM, the general-purpose mouse daemon, with the given
- command-line options. GPM allows users to use the mouse in the console,
- notably to select, copy, and paste text. The default options use the
- @code{ps2} protocol, which works for both USB and PS/2 mice.")))
- (define* (gpm-service #:key (gpm gpm)
- (options '("-m" "/dev/input/mice" "-t" "ps2")))
- "Run @var{gpm}, the general-purpose mouse daemon, with the given
- command-line @var{options}. GPM allows users to use the mouse in the console,
- notably to select, copy, and paste text. The default value of @var{options}
- uses the @code{ps2} protocol, which works for both USB and PS/2 mice.
- This service is not part of @var{%base-services}."
- ;; To test in QEMU, use "-usbdevice mouse" and then, in the monitor, use
- ;; "info mice" and "mouse_set X" to use the right mouse.
- (service gpm-service-type
- (gpm-configuration (gpm gpm) (options options))))
- (define-record-type* <kmscon-configuration>
- kmscon-configuration make-kmscon-configuration
- kmscon-configuration?
- (kmscon kmscon-configuration-kmscon
- (default kmscon))
- (virtual-terminal kmscon-configuration-virtual-terminal)
- (login-program kmscon-configuration-login-program
- (default (file-append shadow "/bin/login")))
- (login-arguments kmscon-configuration-login-arguments
- (default '("-p")))
- (hardware-acceleration? kmscon-configuration-hardware-acceleration?
- (default #f))) ; #t causes failure
- (define kmscon-service-type
- (shepherd-service-type
- 'kmscon
- (lambda (config)
- (let ((kmscon (kmscon-configuration-kmscon config))
- (virtual-terminal (kmscon-configuration-virtual-terminal config))
- (login-program (kmscon-configuration-login-program config))
- (login-arguments (kmscon-configuration-login-arguments config))
- (hardware-acceleration? (kmscon-configuration-hardware-acceleration? config)))
- (define kmscon-command
- #~(list
- #$(file-append kmscon "/bin/kmscon") "--login"
- "--vt" #$virtual-terminal
- #$@(if hardware-acceleration? '("--hwaccel") '())
- "--" #$login-program #$@login-arguments))
- (shepherd-service
- (documentation "kmscon virtual terminal")
- (requirement '(user-processes udev dbus-system))
- (provision (list (symbol-append 'term- (string->symbol virtual-terminal))))
- (start #~(make-forkexec-constructor #$kmscon-command))
- (stop #~(make-kill-destructor)))))))
- (define %base-services
- ;; Convenience variable holding the basic services.
- (list (login-service)
- (service console-font-service-type
- (map (lambda (tty)
- (cons tty %default-console-font))
- '("tty1" "tty2" "tty3" "tty4" "tty5" "tty6")))
- (mingetty-service (mingetty-configuration
- (tty "tty1")))
- (mingetty-service (mingetty-configuration
- (tty "tty2")))
- (mingetty-service (mingetty-configuration
- (tty "tty3")))
- (mingetty-service (mingetty-configuration
- (tty "tty4")))
- (mingetty-service (mingetty-configuration
- (tty "tty5")))
- (mingetty-service (mingetty-configuration
- (tty "tty6")))
- (service static-networking-service-type
- (list (static-networking (interface "lo")
- (ip "127.0.0.1")
- (provision '(loopback)))))
- (syslog-service)
- (urandom-seed-service)
- (guix-service)
- (nscd-service)
- ;; The LVM2 rules are needed as soon as LVM2 or the device-mapper is
- ;; used, so enable them by default. The FUSE and ALSA rules are
- ;; less critical, but handy.
- (udev-service #:rules (list lvm2 fuse alsa-utils crda))
- (service special-files-service-type
- `(("/bin/sh" ,(file-append (canonical-package bash)
- "/bin/sh"))))))
- ;;; base.scm ends here
|