12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383 |
- ;;; GNU Guix --- Functional package management for GNU
- ;;; Copyright © 2013-2023 Ludovic Courtès <ludo@gnu.org>
- ;;; Copyright © 2015, 2016 Alex Kost <alezost@gmail.com>
- ;;; Copyright © 2015, 2016, 2020 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>
- ;;; Copyright © 2018 Mathieu Othacehe <m.othacehe@gmail.com>
- ;;; Copyright © 2019 Efraim Flashner <efraim@flashner.co.il>
- ;;; Copyright © 2019 Tobias Geerinckx-Rice <me@tobias.gr>
- ;;; Copyright © 2019 John Soo <jsoo1@asu.edu>
- ;;; Copyright © 2019, 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
- ;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de>
- ;;; Copyright © 2020, 2021 Brice Waegeneire <brice@waegenei.re>
- ;;; Copyright © 2021 qblade <qblade@protonmail.com>
- ;;; Copyright © 2021 Hui Lu <luhuins@163.com>
- ;;; Copyright © 2021, 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
- ;;; Copyright © 2021 muradm <mail@muradm.net>
- ;;; Copyright © 2022 Guillaume Le Vaillant <glv@posteo.net>
- ;;; Copyright © 2022 Justin Veilleux <terramorpha@cock.li>
- ;;; Copyright © 2022 ( <paren@disroot.org>
- ;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
- ;;;
- ;;; 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 (guix deprecation)
- #:autoload (guix diagnostics) (warning formatted-message &fix-hint)
- #:autoload (guix i18n) (G_)
- #:use-module (guix combinators)
- #:use-module (gnu services)
- #:use-module (gnu services admin)
- #:use-module (gnu services shepherd)
- #:use-module (gnu services sysctl)
- #: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 keyboard)
- #: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 btrfs-progs crda eudev
- e2fsprogs f2fs-tools fuse gpm kbd lvm2 rng-tools
- util-linux xfsprogs))
- #:use-module (gnu packages bash)
- #:use-module ((gnu packages base)
- #:select (coreutils glibc glibc-utf8-locales tar
- canonical-package))
- #:use-module ((gnu packages compression) #:select (gzip))
- #:use-module (gnu packages fonts)
- #:autoload (gnu packages guile-xyz) (guile-netlink)
- #:autoload (gnu packages hurd) (hurd)
- #:use-module (gnu packages package-management)
- #:use-module ((gnu packages gnupg) #:select (guile-gcrypt))
- #:use-module ((gnu packages disk)
- #:select (dosfstools))
- #:use-module ((gnu packages file-systems)
- #:select (bcachefs-tools exfat-utils jfsutils zfs))
- #:use-module (gnu packages fonts)
- #:use-module (gnu packages terminals)
- #:use-module ((gnu packages wm) #:select (sway))
- #:use-module ((gnu build file-systems)
- #:select (mount-flags->bit-mask
- swap-space->flags-bit-mask))
- #:use-module (guix gexp)
- #:use-module (guix records)
- #:use-module (guix modules)
- #:use-module (guix pki)
- #:use-module ((guix self) #:select (make-config.scm))
- #:use-module (guix diagnostics)
- #:use-module (guix i18n)
- #:use-module (srfi srfi-1)
- #:use-module (srfi srfi-26)
- #:use-module (srfi srfi-34)
- #:use-module (srfi srfi-35)
- #:use-module (ice-9 match)
- #:use-module (ice-9 format)
- #:re-export (user-processes-service-type ;backwards compatibility
- %default-substitute-urls)
- #:export (fstab-service-type
- root-file-system-service
- file-system-service-type
- file-system-utilities
- swap-service
- host-name-service ; deprecated
- host-name-service-type
- %default-console-font
- console-font-service-type
- console-font-service
- virtual-terminal-service-type
- host
- host?
- host-address
- host-canonical-name
- host-aliases
- hosts-service-type
- static-networking
- static-networking?
- static-networking-addresses
- static-networking-links
- static-networking-routes
- static-networking-requirement
- network-address
- network-address?
- network-address-device
- network-address-value
- network-address-ipv6?
- network-link
- network-link?
- network-link-name
- network-link-type
- network-link-arguments
- network-route
- network-route?
- network-route-destination
- network-route-source
- network-route-device
- network-route-ipv6?
- network-route-gateway
- static-networking-service
- static-networking-service-type
- %loopback-static-networking
- %qemu-static-networking
- udev-configuration
- udev-configuration?
- udev-configuration-rules
- udev-service-type
- udev-service ; deprecated
- udev-rule
- file->udev-rule
- udev-rules-service
- login-configuration
- login-configuration?
- login-service-type
- login-service ; deprecated
- agetty-configuration
- agetty-configuration?
- agetty-service ; deprecated
- agetty-service-type
- mingetty-configuration
- mingetty-configuration-tty
- mingetty-configuration-auto-login
- mingetty-configuration-login-program
- mingetty-configuration-login-pause?
- mingetty-configuration-clear-on-logout?
- mingetty-configuration-mingetty
- mingetty-configuration?
- mingetty-service ; deprecated
- mingetty-service-type
- %nscd-default-caches
- %nscd-default-configuration ; deprecated
- nscd-configuration
- nscd-configuration?
- nscd-cache
- nscd-cache?
- nscd-service-type
- nscd-service ; deprecated
- syslog-configuration
- syslog-configuration?
- syslog-service ; deprecated
- 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-generate-substitute-key?
- guix-configuration-extra-options
- guix-configuration-log-file
- guix-configuration-environment
- guix-extension
- guix-extension?
- guix-extension-authorized-keys
- guix-extension-substitute-urls
- guix-extension-chroot-directories
- 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
- guix-publish-configuration-nar-path
- guix-publish-configuration-cache
- guix-publish-configuration-ttl
- guix-publish-configuration-negative-ttl
- guix-publish-service-type
- gpm-configuration
- gpm-configuration?
- gpm-service-type
- urandom-seed-service-type
- rngd-configuration
- rngd-configuration?
- rngd-service-type
- rngd-service ; deprecated
- kmscon-configuration
- kmscon-configuration?
- kmscon-service-type
- pam-limits-service-type
- pam-limits-service ; deprecated
- greetd-service-type
- greetd-configuration
- greetd-terminal-configuration
- greetd-agreety-session
- greetd-wlgreet-session
- greetd-wlgreet-sway-session
- %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 (match (file-system-device file-system)
- ((? file-system-label? label)
- (string-append "LABEL="
- (file-system-label->string label)))
- ((? uuid? uuid)
- (string-append "UUID=" (uuid->string uuid)))
- ((? string? device)
- device))
- "\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 Guix 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)
- (let ((null (%make-void-port "w")))
- ;; 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 should be no open files left so the
- ;; root file system can be re-mounted read-only.
- (let loop ((n 10))
- (unless (catch 'system-error
- (lambda ()
- (mount #f "/" #f
- (logior MS_REMOUNT MS_RDONLY)
- #:update-mtab? #f)
- #t)
- (const #f))
- (unless (zero? n)
- ;; Yield to the other fibers. That gives logging fibers
- ;; an opportunity to close log files so the 'mount' call
- ;; doesn't fail with EBUSY.
- ((@ (fibers) sleep) 1)
- (loop (- n 1)))))
- #f)))
- (respawn? #f)))
- (define root-file-system-service-type
- (shepherd-service-type 'root-file-system
- (const %root-file-system-shepherd-service)
- (description "Take care of syncing the root file
- system and of remounting it read-only when the system shuts down.")))
- (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 (string-join
- (mapped-device-targets 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 or doesn't have its mount point created
- upon boot."
- (let ((target (file-system-mount-point file-system))
- (create? (file-system-create-mount-point? file-system))
- (mount? (file-system-mount? file-system))
- (dependencies (file-system-dependencies file-system))
- (packages (file-system-packages (list file-system))))
- (and (or mount? create?)
- (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
- udev
- ,@(map dependency->shepherd-service-name dependencies)))
- (documentation "Check, mount, and unmount the given file system.")
- (start #~(lambda args
- #$(if create?
- #~(mkdir-p #$target)
- #t)
- #$(if mount?
- #~(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
- (spec->file-system
- '#$(file-system->spec file-system))
- #:root "/"))
- (lambda ()
- (setenv "PATH" $PATH))))
- #t)
- #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 additional modules.
- (modules `(((gnu build file-systems)
- #:select (mount-file-system))
- (gnu system file-systems)
- ,@%default-modules)))))))
- (define (file-system-shepherd-services file-systems)
- "Return the list of Shepherd services for FILE-SYSTEMS."
- (let* ((file-systems (filter (lambda (x)
- (or (file-system-mount? x)
- (file-system-create-mount-point? x)))
- 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))))
- (define known-mount-points
- (map file-system-mount-point file-systems))
- (define user-unmount
- (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))))
- (cons* sink user-unmount
- (map file-system-shepherd-service file-systems))))
- (define (file-system-fstab-entries file-systems)
- "Return the subset of @var{file-systems} that should have an entry in
- @file{/etc/fstab}."
- ;; /etc/fstab is about telling fsck(8), mount(8), and umount(8) about
- ;; relevant file systems they'll have to deal with. That excludes "pseudo"
- ;; file systems.
- ;;
- ;; In particular, things like GIO (part of GLib) use it to determine the set
- ;; of mounts, which is then used by graphical file managers and desktop
- ;; environments to display "volume" icons. Thus, we really need to exclude
- ;; those pseudo file systems from the list.
- (remove (lambda (file-system)
- (or (member (file-system-type file-system)
- %pseudo-file-system-types)
- (memq 'bind-mount (file-system-flags file-system))))
- file-systems))
- (define (file-system-type->utilities type)
- "Return the package providing the utilities for file system TYPE, #f
- otherwise."
- (assoc-ref
- `(("bcachefs" . ,bcachefs-tools)
- ("btrfs" . ,btrfs-progs)
- ("exfat" . ,exfat-utils)
- ("ext2" . ,e2fsprogs)
- ("ext3" . ,e2fsprogs)
- ("ext4" . ,e2fsprogs)
- ("fat" . ,dosfstools)
- ("f2fs" . ,f2fs-tools)
- ("jfs" . ,jfsutils)
- ("vfat" . ,dosfstools)
- ("xfs" . ,xfsprogs)
- ("zfs" . ,zfs))
- type))
- (define (file-system-utilities file-systems)
- "Return a list of packages containing file system utilities for
- FILE-SYSTEMS."
- (filter-map (lambda (file-system)
- (file-system-type->utilities (file-system-type file-system)))
- 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
- file-system-fstab-entries)
- (service-extension profile-service-type
- file-system-utilities)
- ;; Have 'user-processes' depend on 'file-systems'.
- (service-extension user-processes-service-type
- (const '(file-systems)))))
- (compose concatenate)
- (extend append)
- (description
- "Provide Shepherd services to mount and unmount the given
- file systems, as well as corresponding @file{/etc/fstab} entries.")))
- ;;;
- ;;; 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))
- ;; Depend on udev so that /dev/hwrng is available.
- (requirement '(file-systems udev))
- (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)
- ;; Writing SEED to URANDOM isn't enough: we must
- ;; also tell the kernel to account for these
- ;; extra bits of entropy.
- (let ((bits (* 8 (stat:size (stat seed)))))
- (add-to-entropy-count urandom bits)))))))
- ;; Try writing from /dev/hwrng into /dev/urandom.
- ;; It seems that the file /dev/hwrng always exists, even
- ;; when there is no hardware random number generator
- ;; available. So, we handle a failed read or any other error
- ;; reported by the operating system.
- (let ((buf (catch 'system-error
- (lambda ()
- (call-with-input-file "/dev/hwrng"
- (lambda (hwrng)
- (get-bytevector-n hwrng 512))))
- ;; Silence is golden...
- (const #f))))
- (when buf
- (call-with-output-file "/dev/urandom"
- (lambda (urandom)
- (put-bytevector urandom buf)
- (let ((bits (* 8 (bytevector-length buf))))
- (add-to-entropy-count urandom bits))))))
- ;; 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)
- ;; Have 'user-processes' depend on 'urandom-seed'.
- ;; This ensures that user processes and daemons don't
- ;; start until we have seeded the PRNG.
- (service-extension user-processes-service-type
- (const '(urandom-seed)))))
- (default-value #f)
- (description
- "Seed the @file{/dev/urandom} pseudo-random number
- generator (RNG) with the value recorded when the system was last shut
- down.")))
- ;;;
- ;;; 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 ;file-like
- (default rng-tools))
- (device rngd-configuration-device ;string
- (default "/dev/hwrng")))
- (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))))
- (rngd-configuration)
- (description "Run the @command{rngd} random number generation daemon to
- supply entropy to the kernel's pool.")))
- (define-deprecated (rngd-service #:key (rng-tools rng-tools)
- (device "/dev/hwrng"))
- rngd-service-type
- "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))))
- ;;;
- ;;; /etc/hosts
- ;;;
- (eval-when (expand load eval)
- (define (valid-name? name)
- "Return true if @var{name} is likely to be a valid host name."
- (false-if-exception (not (string-any char-set:whitespace name)))))
- (define-compile-time-procedure (assert-valid-name (name valid-name?))
- "Ensure @var{name} is likely to be a valid host name."
- ;; TODO: RFC compliant implementation.
- (unless (valid-name? name)
- (raise
- (make-compound-condition
- (formatted-message (G_ "host name '~a' contains invalid characters")
- name)
- (condition (&error-location
- (location
- (source-properties->location procedure-call-location)))))))
- name)
- (define-record-type* <host> %host
- ;; XXX: Using the record type constructor becomes tiresome when
- ;; there's multiple records to make.
- make-host host?
- (address host-address)
- (canonical-name host-canonical-name
- (sanitize assert-valid-name))
- (aliases host-aliases
- (default '())
- (sanitize (cut map assert-valid-name <>))))
- (define* (host address canonical-name #:optional (aliases '()))
- "Return a new record for the host at @var{address} with the given
- @var{canonical-name} and possibly @var{aliases}.
- @var{address} must be a string denoting a valid IPv4 or IPv6 address, and
- @var{canonical-name} and the strings listed in @var{aliases} must be valid
- host names."
- (%host
- (address address)
- (canonical-name canonical-name)
- (aliases aliases)))
- (define hosts-service-type
- ;; Extend etc-service-type with a entry for @file{/etc/hosts}.
- (let* ((serialize-host-record
- (lambda (record)
- (match-record record <host> (address canonical-name aliases)
- (format #f "~a~/~a~{~^~/~a~}~%" address canonical-name aliases))))
- (host-etc-service
- (lambda (lst)
- `(("hosts" ,(plain-file "hosts"
- (format #f "~{~a~}"
- (map serialize-host-record
- lst))))))))
- (service-type
- (name 'etc-hosts)
- (extensions
- (list
- (service-extension etc-service-type
- host-etc-service)))
- (compose concatenate)
- (extend append)
- (description "Populate the @file{/etc/hosts} file."))))
- ;;;
- ;;; 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)))
- (one-shot? #t)))
- (description "Initialize the machine's host name.")))
- (define-deprecated (host-name-service name)
- host-name-service-type
- "Return a service that sets the host name to @var{name}."
- (service host-name-service-type name))
- (define virtual-terminal-service-type
- ;; Ensure that virtual terminals run in UTF-8 mode. This is the case by
- ;; default with recent Linux kernels, but this service allows us to ensure
- ;; this. This service must start before any 'term-' service so that newly
- ;; created terminals inherit this property. See
- ;; <https://bugs.gnu.org/30505> for a discussion.
- (shepherd-service-type
- 'virtual-terminal
- (lambda (utf8?)
- (let ((knob "/sys/module/vt/parameters/default_utf8"))
- (shepherd-service
- (documentation "Set virtual terminals in UTF-8 module.")
- (provision '(virtual-terminal))
- (requirement '(root-file-system))
- (start #~(lambda _
- ;; In containers /sys is read-only so don't insist on
- ;; writing to this file.
- (unless (= 1 (call-with-input-file #$knob read))
- (call-with-output-file #$knob
- (lambda (port)
- (display 1 port))))
- #t))
- (stop #~(const #f)))))
- #t ;default to UTF-8
- (description "Ensure the Linux virtual terminals run in UTF-8 mode.")))
- (define %default-console-font
- ;; Note: the 'font-gnu-unifont' package cannot be cross-compiled (yet), but
- ;; its "psf" output is the same whether it's built natively or not, hence
- ;; 'ungexp-native'.
- #~(string-append #+font-gnu-unifont:psf
- "/share/consolefonts/Unifont-APL8x16.psf.gz"))
- (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 _
- ;; It could be that mingetty is not fully ready yet,
- ;; which we check by calling 'ttyname'.
- (let loop ((i 10))
- (unless (or (zero? i)
- (call-with-input-file #$device
- (lambda (port)
- (false-if-exception (ttyname port)))))
- (usleep 500)
- (loop (- i 1))))
- ;; Assume the VT is already in UTF-8 mode, thanks to
- ;; the 'virtual-terminal' service.
- ;;
- ;; 'setfont' returns EX_OSERR (71) when an
- ;; KDFONTOP ioctl fails, for example. Like
- ;; systemd's vconsole support, let's not treat
- ;; this as an error.
- (case (status:exit-val
- (system* #$(file-append kbd "/bin/setfont")
- "-C" #$device #$font))
- ((0 71) #t)
- (else #f))))
- (stop #~(const #f))
- (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. The font can be the name of a font provided by the @code{kbd}
- package or any valid argument to @command{setfont}, as in this example:
- @example
- `((\"tty1\" . \"LatGrkCyr-8x16\")
- (\"tty2\" . ,(file-append
- font-tamzen
- \"/share/kbd/consolefonts/TamzenForPowerline10x20.psf\"))
- (\"tty3\" . ,(file-append
- font-terminus
- \"/share/consolefonts/ter-132n\"))) ; for HDPI
- @end example\n")))
- (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"
- #:login-uid? #t
- #: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)))
- (default-value (login-configuration))
- (description
- "Provide a console log-in service as specified by its
- configuration value, a @code{login-configuration} object.")))
- (define-deprecated (login-service #:optional (config (login-configuration)))
- login-service-type
- "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 ;file-like
- (default util-linux))
- (tty agetty-configuration-tty) ;string | #f
- (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 '()))
- (shepherd-requirement agetty-shepherd-requirement ;list of SHEPHERD requirements
- (default '()))
- ;;; XXX Unimplemented for now!
- ;;; (issue-file agetty-issue-file ;file-like
- ;;; (default #f))
- )
- (define (default-serial-port)
- "Return a gexp that determines a reasonable default serial port
- to use as the tty. This is primarily useful for headless systems."
- (with-imported-modules (source-module-closure
- '((gnu build linux-boot))) ;for 'find-long-options'
- #~(begin
- ;; console=device,options
- ;; device: can be tty0, ttyS0, lp0, ttyUSB0 (serial).
- ;; options: BBBBPNF. P n|o|e, N number of bits,
- ;; F flow control (r RTS)
- (let* ((not-comma (char-set-complement (char-set #\,)))
- (command (linux-command-line))
- (agetty-specs (find-long-options "agetty.tty" command))
- (console-specs (filter (lambda (spec)
- (and (string-prefix? "tty" spec)
- (not (or
- (string-prefix? "tty0" spec)
- (string-prefix? "tty1" spec)
- (string-prefix? "tty2" spec)
- (string-prefix? "tty3" spec)
- (string-prefix? "tty4" spec)
- (string-prefix? "tty5" spec)
- (string-prefix? "tty6" spec)
- (string-prefix? "tty7" spec)
- (string-prefix? "tty8" spec)
- (string-prefix? "tty9" spec)))))
- (find-long-options "console" command)))
- (specs (append agetty-specs console-specs)))
- (match specs
- (() #f)
- ((spec _ ...)
- ;; Extract device name from first spec.
- (match (string-tokenize spec not-comma)
- ((device-name _ ...)
- device-name))))))))
- (define (agetty-shepherd-service config)
- (match-record config <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
- shepherd-requirement)
- (list
- (shepherd-service
- (documentation "Run agetty on a tty.")
- (provision (list (symbol-append 'term- (string->symbol (or tty "console")))))
- ;; 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 (cons* 'user-processes 'host-name 'udev
- shepherd-requirement))
- (modules '((ice-9 match) (gnu build linux-boot)))
- (start
- (with-imported-modules (source-module-closure
- '((gnu build linux-boot)))
- #~(lambda args
- (let ((defaulted-tty #$(or tty (default-serial-port))))
- (apply
- (if defaulted-tty
- (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 tty
- #~()
- #~("--keep-baud"))
- #$@(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")
- #~())
- defaulted-tty
- #$@(if baud-rate
- #~(#$baud-rate)
- #~())
- #$@(if term
- #~(#$term)
- #~())))
- #$(if tty
- #~(const #f) ;always fail to start
- #~(lambda _ ;succeed, but don't do anything
- (format #t "~a: \
- no serial port console requested; doing nothing~%"
- '#$(car provision))
- 'idle)))
- args)))))
- (stop #~(let ((stop (make-kill-destructor)))
- (lambda (running)
- (if (eq? 'idle running)
- #f
- (stop running)))))))))
- (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-deprecated (agetty-service config)
- agetty-service-type
- "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 ;file-like
- (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))
- (clear-on-logout? mingetty-clear-on-logout? ;Boolean
- (default #t)))
- (define (mingetty-shepherd-service config)
- (match-record config <mingetty-configuration>
- (mingetty tty auto-login login-program
- login-pause? clear-on-logout?)
- (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 virtual-terminal))
- (start #~(make-forkexec-constructor
- (list #$(file-append mingetty "/sbin/mingetty")
- ;; Avoiding 'vhangup' allows us to avoid 'setfont'
- ;; errors down the path where various ioctls get
- ;; EIO--see 'hung_up_tty_ioctl' in driver/tty/tty_io.c
- ;; in Linux.
- "--nohangup" #$tty
- #$@(if clear-on-logout?
- #~()
- #~("--noclear"))
- #$@(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-deprecated (mingetty-service config)
- mingetty-service-type
- "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 file-like
- (default '()))
- (glibc nscd-configuration-glibc ;file-like
- (default (let-system (system target)
- ;; Unless we're cross-compiling, arrange to use nscd
- ;; from 'glibc-final' instead of pulling in a second
- ;; glibc copy.
- (if target
- glibc
- (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-deprecated %nscd-default-configuration
- #f
- ;; 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 cache)
- (match-record cache <nscd-cache>
- (database positive-time-to-live negative-time-to-live
- suggested-size check-files?
- persistent? shared? max-database-size auto-propagate?)
- (let ((database (symbol->string database)))
- (string-append "\nenable-cache\t" database "\tyes\n"
- "positive-time-to-live\t" database "\t"
- (number->string positive-time-to-live) "\n"
- "negative-time-to-live\t" database "\t"
- (number->string negative-time-to-live) "\n"
- "suggested-size\t" database "\t"
- (number->string suggested-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-database-size) "\n"
- "auto-propagate\t" database "\t"
- (if auto-propagate? "yes\n" "no\n")))))
- (match-record 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-action-procedure nscd config option)
- ;; XXX: This is duplicated from mcron; factorize.
- #~(lambda (_ . args)
- ;; Run 'nscd' in a pipe so we can explicitly redirect its output to
- ;; 'current-output-port', which at this stage is bound to the client
- ;; connection.
- (let ((pipe (apply open-pipe* OPEN_READ #$nscd
- "-f" #$config #$option args)))
- (let loop ()
- (match (read-line pipe 'concat)
- ((? eof-object?)
- (catch 'system-error
- (lambda ()
- (zero? (close-pipe pipe)))
- (lambda args
- ;; There's a race with the SIGCHLD handler, which could
- ;; call 'waitpid' before 'close-pipe' above does. If we
- ;; get ECHILD, that means we lost the race; in that case, we
- ;; cannot tell what the exit code was (FIXME).
- (or (= ECHILD (system-error-errno args))
- (apply throw args)))))
- (line
- (display line)
- (loop)))))))
- (define (nscd-actions nscd config)
- "Return Shepherd actions for NSCD using CONFIG its config file."
- ;; Make this functionality available as actions because that's a simple way
- ;; to run the right 'nscd' binary with the right config file.
- (list (shepherd-configuration-action config)
- (shepherd-action
- (name 'statistics)
- (documentation "Display statistics about nscd usage.")
- (procedure (nscd-action-procedure nscd config "--statistics")))
- (shepherd-action
- (name 'invalidate)
- (documentation
- "Invalidate the given cache--e.g., 'hosts' for host name lookups.")
- (procedure (nscd-action-procedure nscd config "--invalidate")))))
- (define (nscd-shepherd-service config)
- "Return a shepherd service for CONFIG, an <nscd-configuration> object."
- (let ((nscd (file-append (nscd-configuration-glibc config)
- "/sbin/nscd"))
- (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))
- ;; Logs are written with syslog(3), which writes to /dev/console
- ;; when nobody's listening--ugly. Thus, wait for syslogd.
- (requirement '(user-processes syslogd))
- (start #~(make-forkexec-constructor
- (list #$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))
- (modules `((ice-9 popen) ;for the actions
- (ice-9 rdelim)
- (ice-9 match)
- ,@%default-modules))
- (actions (nscd-actions nscd nscd.conf))))))
- (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)))))
- (default-value (nscd-configuration))
- (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-deprecated (nscd-service #:optional (config (nscd-configuration)))
- nscd-service-type
- "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))
- ;;; Snippet adapted from the GNU inetutils manual.
- (define %default-syslog.conf
- (plain-file "syslog.conf" "\
- # See info '(inetutils) syslogd invocation' for the documentation
- # of the syslogd configuration syntax.
- # 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
- # Log \"debug\"-level entries and nothing else.
- *.=debug -/var/log/debug
- # Same, in a different place.
- *.info;mail.none;authpriv.none -/dev/tty12
- # The authpriv file has restricted access.
- # 'fsync' the file after each line (hence the lack of a leading dash).
- # Also include unprivileged auth logs of info or higher level
- # to conveniently gather the authentication data at the same place.
- authpriv.*;auth.info /var/log/secure
- # Log all the mail messages in one place.
- mail.* -/var/log/maillog
- "))
- (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)))
- ;;; Note: a static file name is used for syslog.conf so that the reload action
- ;;; work as intended.
- (define syslog.conf "/etc/syslog.conf")
- (define (syslog-etc configuration)
- (match-record configuration <syslog-configuration>
- (config-file)
- (list `(,(basename syslog.conf) ,config-file))))
- (define (syslog-shepherd-service config)
- (define config-file
- (syslog-configuration-config-file config))
- (shepherd-service
- (documentation "Run the syslog daemon (syslogd).")
- (provision '(syslogd))
- (requirement '(user-processes))
- (actions
- (list (shepherd-configuration-action syslog.conf)
- (shepherd-action
- (name 'reload)
- (documentation "Reload the configuration file from disk.")
- (procedure
- #~(lambda (pid)
- (if pid
- (begin
- (kill pid SIGHUP)
- (display #$(G_ "Service syslog has been asked to \
- reload its settings file.")))
- (display #$(G_ "Service syslog is not running."))))))))
- ;; Note: a static file name is used for syslog.conf so that the reload
- ;; action work as intended.
- (start #~(make-forkexec-constructor
- (list #$(syslog-configuration-syslogd config)
- #$(string-append "--rcfile=" syslog.conf))
- #:file-creation-mask #o137
- #:pid-file "/var/run/syslog.pid"))
- (stop #~(make-kill-destructor))))
- (define syslog-service-type
- (service-type
- (name 'syslog)
- (default-value (syslog-configuration))
- (extensions (list (service-extension shepherd-root-service-type
- (compose list syslog-shepherd-service))
- (service-extension etc-service-type syslog-etc)))
- (description "Run the syslog daemon, @command{syslogd}, which is
- responsible for logging system messages.")))
- (define-deprecated (syslog-service #:optional (config (syslog-configuration)))
- syslog-service-type
- "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 ((pam-extension
- (lambda (limits-file)
- (pam-extension
- (transformer
- (lambda (pam)
- (let ((pam-limits (pam-entry
- (control "required")
- (module "pam_limits.so")
- (arguments
- (list #~(string-append "conf=" #$limits-file))))))
- (if (member (pam-service-name pam)
- '("login" "greetd" "su" "slim" "gdm-password"
- "sddm" "lightdm" "sudo" "sshd"))
- (pam-service
- (inherit pam)
- (session (cons pam-limits
- (pam-service-session pam))))
- pam)))))))
- (make-limits-file
- (match-lambda
- ;; XXX: Using file-like objects is deprecated, use lists instead.
- ;; This is to be reduced into the list? case when the deprecated
- ;; code gets removed.
- ((? file-like? obj)
- (warning (G_ "Using file-like value for \
- 'pam-limits-service-type' is deprecated~%"))
- obj)
- ((? list? lst)
- (plain-file "limits.conf"
- (string-join (map pam-limits-entry->string lst)
- "\n" 'suffix)))
- (_ (raise
- (formatted-message
- (G_ "invalid input for 'pam-limits-service-type'~%")))))))
- (service-type
- (name 'limits)
- (extensions
- (list (service-extension pam-root-service-type
- (lambda (config)
- (list (pam-extension (make-limits-file config)))))))
- (description
- "Use the @code{pam_limits} authentication module to set the specified
- resource usage limits.")
- (default-value '()))))
- (define-deprecated (pam-limits-service #:optional (limits '()))
- pam-limits-service-type
- "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")
- (shadow shadow))
- "Return a list of COUNT user accounts for Guix build users with the given
- GID."
- (unfold (cut > <> count)
- (lambda (n)
- (user-account
- (name (format #f "guixbuilder~2,'0d" n))
- (system? #t)
- (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 not-config?
- ;; Select (guix …) and (gnu …) modules, except (guix config).
- (match-lambda
- (('guix 'config) #f)
- (('guix rest ...) #t)
- (('gnu rest ...) #t)
- (rest #f)))
- (define (substitute-key-authorization keys guix)
- "Return a gexp with code to register KEYS, a list of files containing 'guix
- archive' public keys, with GUIX."
- (define default-acl
- (with-extensions (list guile-gcrypt)
- (with-imported-modules `(((guix config) => ,(make-config.scm))
- ,@(source-module-closure '((guix pki))
- #:select? not-config?))
- (computed-file "acl"
- #~(begin
- (use-modules (guix pki)
- (gcrypt pk-crypto)
- (ice-9 rdelim))
- (define keys
- (map (lambda (file)
- (call-with-input-file file
- (compose string->canonical-sexp
- read-string)))
- '(#$@keys)))
- (call-with-output-file #$output
- (lambda (port)
- (write-acl (public-keys->acl keys)
- port))))))))
- (with-imported-modules '((guix build utils))
- #~(begin
- (use-modules (guix build utils))
- (define acl-file #$%acl-file)
- ;; If the ACL already exists, move it out of the way. Create a backup
- ;; if it's a regular file: it's likely that the user manually updated
- ;; it with 'guix archive --authorize'.
- (if (file-exists? acl-file)
- (if (and (symbolic-link? acl-file)
- (store-file-name? (readlink acl-file)))
- (delete-file acl-file)
- (rename-file acl-file (string-append acl-file ".bak")))
- (mkdir-p (dirname acl-file)))
- ;; Installed the declared ACL.
- (symlink #+default-acl acl-file))))
- (define %default-authorized-guix-keys
- ;; List of authorized substitute keys.
- (list (file-append guix "/share/guix/berlin.guix.gnu.org.pub")
- (file-append guix "/share/guix/bordeaux.guix.gnu.org.pub")))
- (define-record-type* <guix-configuration>
- guix-configuration make-guix-configuration
- guix-configuration?
- (guix guix-configuration-guix ;file-like
- (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))
- (generate-substitute-key? guix-configuration-generate-substitute-key?
- (default #t)) ;Boolean
- (chroot-directories guix-configuration-chroot-directories ;list of file-like/strings
- (default '()))
- (max-silent-time guix-configuration-max-silent-time ;integer
- (default 0))
- (timeout guix-configuration-timeout ;integer
- (default 0))
- (log-compression guix-configuration-log-compression
- (default 'gzip))
- (discover? guix-configuration-discover?
- (default #f))
- (extra-options guix-configuration-extra-options ;list of strings
- (default '()))
- (log-file guix-configuration-log-file ;string
- (default "/var/log/guix-daemon.log"))
- (http-proxy guix-http-proxy ;string | #f
- (default #f))
- (tmpdir guix-tmpdir ;string | #f
- (default #f))
- (environment guix-configuration-environment ;list of strings
- (default '())))
- (define %default-guix-configuration
- (guix-configuration))
- (define shepherd-set-http-proxy-action
- ;; Shepherd action to change the HTTP(S) proxy.
- (shepherd-action
- (name 'set-http-proxy)
- (documentation
- "Change the HTTP(S) proxy used by 'guix-daemon' and restart it.")
- (procedure #~(lambda* (_ #:optional proxy)
- (let ((environment (environ)))
- ;; A bit of a hack: communicate PROXY to the 'start'
- ;; method via environment variables.
- (if proxy
- (begin
- (format #t "changing HTTP/HTTPS \
- proxy of 'guix-daemon' to ~s...~%"
- proxy)
- (setenv "http_proxy" proxy))
- (begin
- (format #t "clearing HTTP/HTTPS \
- proxy of 'guix-daemon'...~%")
- (unsetenv "http_proxy")))
- (action 'guix-daemon 'restart)
- (environ environment)
- #t)))))
- (define shepherd-discover-action
- ;; Shepherd action to enable or disable substitute servers discovery.
- (shepherd-action
- (name 'discover)
- (documentation
- "Enable or disable substitute servers discovery and restart the
- 'guix-daemon'.")
- (procedure #~(lambda* (_ status)
- (let ((environment (environ)))
- (if (and status
- (string=? status "on"))
- (begin
- (format #t "enable substitute servers discovery~%")
- (setenv "discover" "on"))
- (begin
- (format #t "disable substitute servers discovery~%")
- (unsetenv "discover")))
- (action 'guix-daemon 'restart)
- (environ environment)
- #t)))))
- (define (guix-shepherd-service config)
- "Return a <shepherd-service> for the Guix daemon service with CONFIG."
- (match-record config <guix-configuration>
- (guix build-group build-accounts authorize-key? authorized-keys
- use-substitutes? substitute-urls max-silent-time timeout
- log-compression discover? extra-options log-file
- http-proxy tmpdir chroot-directories environment)
- (list (shepherd-service
- (documentation "Run the Guix daemon.")
- (provision '(guix-daemon))
- (requirement `(user-processes
- ,@(if discover? '(avahi-daemon) '())))
- (actions (list shepherd-set-http-proxy-action
- shepherd-discover-action))
- (modules '((srfi srfi-1)
- (ice-9 match)
- (gnu build shepherd)))
- (start
- (with-imported-modules `(((guix config) => ,(make-config.scm))
- ,@(source-module-closure
- '((gnu build shepherd))
- #:select? not-config?))
- #~(lambda args
- (define proxy
- ;; HTTP/HTTPS proxy. The 'http_proxy' variable is set by
- ;; the 'set-http-proxy' action.
- (or (getenv "http_proxy") #$http-proxy))
- (define discover?
- (or (getenv "discover") #$discover?))
- ;; Start the guix-daemon from a container, when supported,
- ;; to solve an installation issue. See the comment below for
- ;; more details.
- (fork+exec-command/container
- (cons* #$(file-append guix "/bin/guix-daemon")
- "--build-users-group" #$build-group
- "--max-silent-time"
- #$(number->string max-silent-time)
- "--timeout" #$(number->string timeout)
- "--log-compression"
- #$(symbol->string log-compression)
- #$@(if use-substitutes?
- '()
- '("--no-substitutes"))
- (string-append "--discover="
- (if discover? "yes" "no"))
- "--substitute-urls" #$(string-join substitute-urls)
- #$@extra-options
- ;; Add CHROOT-DIRECTORIES and all their dependencies
- ;; (if these are store items) to the chroot.
- (append-map
- (lambda (file)
- (append-map (lambda (directory)
- (list "--chroot-directory"
- directory))
- (call-with-input-file file
- read)))
- '#$(map references-file
- chroot-directories)))
- ;; When running the installer, we need guix-daemon to
- ;; operate from within the same MNT namespace as the
- ;; installation container. In that case only, enter the
- ;; namespace of the process PID passed as start argument.
- ;; Otherwise, for symmetry purposes enter the caller
- ;; namespaces which is a no-op.
- #:pid (match args
- ((pid) (string->number pid))
- (else (getpid)))
- #:environment-variables
- (append (list #$@(if tmpdir
- (list (string-append "TMPDIR=" tmpdir))
- '())
- ;; Make sure we run in a UTF-8 locale so that
- ;; 'guix offload' correctly restores nars
- ;; that contain UTF-8 file names such as
- ;; 'nss-certs'. See
- ;; <https://bugs.gnu.org/32942>.
- (string-append "GUIX_LOCPATH="
- #$glibc-utf8-locales
- "/lib/locale")
- "LC_ALL=en_US.utf8"
- ;; Make 'tar' and 'gzip' available so
- ;; that 'guix perform-download' can use
- ;; them when downloading from Software
- ;; Heritage via '(guix swh)'.
- (string-append "PATH="
- #$(file-append tar "/bin") ":"
- #$(file-append gzip "/bin")))
- (if proxy
- (list (string-append "http_proxy=" proxy)
- (string-append "https_proxy=" proxy))
- '())
- '#$environment)
- #:log-file #$log-file))))
- (stop #~(make-kill-destructor))))))
- (define (guix-accounts config)
- "Return the user accounts and user groups for CONFIG."
- (cons (user-group
- (name (guix-configuration-build-group config))
- (system? #t)
- ;; Use a fixed GID so that we can create the store with the right
- ;; owner.
- (id 30000))
- (guix-build-accounts (guix-configuration-build-accounts config)
- #:group (guix-configuration-build-group config))))
- (define (guix-activation config)
- "Return the activation gexp for CONFIG."
- (match-record config <guix-configuration>
- (guix generate-substitute-key? authorize-key? authorized-keys)
- #~(begin
- ;; Assume that the store has BUILD-GROUP as its group. We could
- ;; otherwise call 'chown' here, but the problem is that on a COW overlayfs,
- ;; chown leads to an entire copy of the tree, which is a bad idea.
- ;; Generate a key pair and optionally authorize substitute server keys.
- (unless (or #$(not generate-substitute-key?)
- (file-exists? "/etc/guix/signing-key.pub"))
- (system* #$(file-append guix "/bin/guix") "archive"
- "--generate-key"))
- #$(if authorize-key?
- (substitute-key-authorization authorized-keys guix)
- #~#f))))
- (define-record-type* <guix-extension>
- guix-extension make-guix-extension
- guix-extension?
- (authorized-keys guix-extension-authorized-keys ;list of file-like
- (default '()))
- (substitute-urls guix-extension-substitute-urls ;list of strings
- (default '()))
- (chroot-directories guix-extension-chroot-directories ;list of file-like/strings
- (default '())))
- (define (guix-extension-merge a b)
- (guix-extension
- (authorized-keys (append (guix-extension-authorized-keys a)
- (guix-extension-authorized-keys b)))
- (substitute-urls (append (guix-extension-substitute-urls a)
- (guix-extension-substitute-urls b)))
- (chroot-directories (append (guix-extension-chroot-directories a)
- (guix-extension-chroot-directories b)))))
- (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))))
- ;; Extensions can specify extra directories to add to the build chroot,
- ;; extra substitute urls and extra authorized keys
- (compose (lambda (args) (fold guix-extension-merge (guix-extension) args)))
- (extend (lambda (config extension)
- (guix-configuration
- (inherit config)
- (authorized-keys (append (guix-extension-authorized-keys extension)
- (guix-configuration-authorized-keys config)))
- (substitute-urls (append (guix-extension-substitute-urls extension)
- (guix-configuration-substitute-urls config)))
- (chroot-directories
- (append (guix-extension-chroot-directories extension)
- (guix-configuration-chroot-directories config))))))
- (default-value (guix-configuration))
- (description
- "Run the build daemon of GNU@tie{}Guix, aka. @command{guix-daemon}.")))
- (define-record-type* <guix-publish-configuration>
- guix-publish-configuration make-guix-publish-configuration
- guix-publish-configuration?
- (guix guix-publish-configuration-guix ;file-like
- (default guix))
- (port guix-publish-configuration-port ;number
- (default 80))
- (host guix-publish-configuration-host ;string
- (default "localhost"))
- (advertise? guix-publish-advertise? ;boolean
- (default #f))
- (compression guix-publish-configuration-compression
- (thunked)
- (default (default-compression this-record)))
- (nar-path guix-publish-configuration-nar-path ;string
- (default "nar"))
- (cache guix-publish-configuration-cache ;#f | string
- (default #f))
- (cache-bypass-threshold guix-publish-configuration-cache-bypass-threshold
- (default (* 10 (expt 2 20)))) ;integer
- (workers guix-publish-configuration-workers ;#f | integer
- (default #f))
- (ttl guix-publish-configuration-ttl ;#f | integer
- (default #f))
- (negative-ttl guix-publish-configuration-negative-ttl ;#f | integer
- (default #f)))
- (define (default-compression config)
- "Return the default 'guix publish' compression according to CONFIG, and
- raise a deprecation warning if the 'compression-level' field was used."
- ;; Default to low compression levels when there's no cache so that users
- ;; get good bandwidth by default.
- (if (guix-publish-configuration-cache config)
- '(("gzip" 5) ("zstd" 19))
- '(("gzip" 3) ("zstd" 3)))) ;zstd compresses faster
- (define (guix-publish-shepherd-service config)
- (define (config->compression-options config)
- (match (guix-publish-configuration-compression config)
- (() ;empty list means "no compression"
- '("-C0"))
- (lst
- (append-map (match-lambda
- ((type level)
- `("-C" ,(string-append type ":"
- (number->string level)))))
- lst))))
- (match-record config <guix-publish-configuration>
- (guix port host nar-path cache workers ttl negative-ttl
- cache-bypass-threshold advertise?)
- (let ((command #~(list #$(file-append guix "/bin/guix")
- "publish" "-u" "guix-publish"
- "-p" #$(number->string port)
- #$@(config->compression-options config)
- (string-append "--nar-path=" #$nar-path)
- (string-append "--listen=" #$host)
- #$@(if advertise?
- #~("--advertise")
- #~())
- #$@(if workers
- #~((string-append "--workers="
- #$(number->string
- workers)))
- #~())
- #$@(if ttl
- #~((string-append "--ttl="
- #$(number->string ttl)
- "s"))
- #~())
- #$@(if negative-ttl
- #~((string-append "--negative-ttl="
- #$(number->string negative-ttl)
- "s"))
- #~())
- #$@(if cache
- #~((string-append "--cache=" #$cache)
- #$(string-append
- "--cache-bypass-threshold="
- (number->string
- cache-bypass-threshold)))
- #~())))
- (options #~(#:environment-variables
- ;; 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>.
- (list (string-append "GUIX_LOCPATH="
- #$glibc-utf8-locales "/lib/locale")
- "LC_ALL=en_US.utf8")
- #:log-file "/var/log/guix-publish.log"))
- (endpoints #~(let ((ai (false-if-exception
- (getaddrinfo #$host
- #$(number->string port)
- AI_NUMERICSERV))))
- (if (pair? ai)
- (list (endpoint (addrinfo:addr (car ai))))
- '()))))
- (list (shepherd-service
- (provision '(guix-publish))
- (requirement `(user-processes
- guix-daemon
- ,@(if advertise? '(avahi-daemon) '())))
- ;; Use lazy socket activation unless ADVERTISE? is true: in that
- ;; case the process should start right away to advertise itself.
- (start #~(if (and (defined? 'make-systemd-constructor) ;> 0.9.0?
- #$(not advertise?))
- (make-systemd-constructor
- #$command #$endpoints #$@options)
- (make-forkexec-constructor #$command #$@options)))
- (stop #~(if (and (defined? 'make-systemd-destructor)
- #$(not advertise?))
- (make-systemd-destructor)
- (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-log-rotations
- (list (log-rotation
- (files (list "/var/log/guix-publish.log"))
- (options `("rotate 4" ;don't keep too many of them
- ,@%default-log-rotation-options)))))
- (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 rottlog-service-type
- (const %guix-publish-log-rotations))
- (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.")))
- ;;;
- ;;; Udev.
- ;;;
- (define-record-type* <udev-configuration>
- udev-configuration make-udev-configuration
- udev-configuration?
- (udev udev-configuration-udev ;file-like
- (default eudev))
- (rules udev-configuration-rules ;list of file-like
- (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)))
- (union-build #$output
- (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 (file->udev-rule file-name file)
- "Return a directory with a udev rule file FILE-NAME which is a copy of FILE."
- (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"))
- (define file-copy-dest
- (string-append rules.d "/" #$file-name))
- (mkdir-p rules.d)
- (copy-file #$file file-copy-dest)))))
- (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 config)
- ;; Return a <shepherd-service> for UDEV with RULES.
- (let ((udev (udev-configuration-udev config)))
- (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
- (with-imported-modules (source-module-closure
- '((gnu build linux-boot)))
- #~(lambda ()
- (define udevd
- ;; 'udevd' from eudev.
- #$(file-append udev "/sbin/udevd"))
- (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")
- (let* ((kernel-release
- (utsname:release (uname)))
- (linux-module-directory
- (getenv "LINUX_MODULE_DIRECTORY"))
- (directory
- (string-append linux-module-directory "/"
- kernel-release))
- (old-umask (umask #o022)))
- ;; If we're in a container, DIRECTORY might not exist,
- ;; for instance because the host runs a different
- ;; kernel. In that case, skip it; we'll just miss a few
- ;; nodes like /dev/fuse.
- (when (file-exists? directory)
- (make-static-device-nodes directory))
- (umask old-umask))
- (let ((pid (fork+exec-command
- (list udevd)
- #:environment-variables
- (cons*
- ;; The first one is for udev, the second one for
- ;; eudev.
- "UDEV_CONFIG_FILE=/etc/udev/udev.conf"
- "EUDEV_RULES_DIRECTORY=/etc/udev/rules.d"
- (string-append "LINUX_MODULE_DIRECTORY="
- (getenv "LINUX_MODULE_DIRECTORY"))
- (default-environment-variables)))))
- ;; 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)
- ;; We need additional modules.
- (modules `((gnu build linux-boot) ;'make-static-device-nodes'
- ,@%default-modules))))))
- (define udev.conf
- (computed-file "udev.conf"
- #~(call-with-output-file #$output
- (lambda (port)
- (format port "udev_rules=\"/etc/udev/rules.d\"~%")))))
- (define (udev-etc config)
- (match-record config <udev-configuration>
- (udev rules)
- `(("udev"
- ,(file-union "udev"
- `(("udev.conf" ,udev.conf)
- ("rules.d"
- ,(udev-rules-union (cons* udev kvm-udev-rule
- rules)))))))))
- (define udev-service-type
- (service-type (name 'udev)
- (extensions
- (list (service-extension shepherd-root-service-type
- udev-shepherd-service)
- (service-extension etc-service-type udev-etc)))
- (compose concatenate) ;concatenate the list of rules
- (extend (lambda (config rules)
- (let ((initial-rules
- (udev-configuration-rules config)))
- (udev-configuration
- (inherit config)
- (rules (append initial-rules rules))))))
- (default-value (udev-configuration))
- (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-deprecated (udev-service #:key (udev eudev) (rules '()))
- udev-service-type
- "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* (udev-rules-service name rules #:key (groups '()))
- "Return a service that extends udev-service-type with RULES and
- account-service-type with GROUPS as system groups. This works by creating a
- singleton service type NAME-udev-rules, of which the returned service is an
- instance."
- (let* ((name (symbol-append name '-udev-rules))
- (account-extension
- (const (map (lambda (group)
- (user-group (name group) (system? #t)))
- groups)))
- (udev-extension (const (list rules)))
- (type (service-type
- (name name)
- (extensions (list
- (service-extension
- account-service-type account-extension)
- (service-extension
- udev-service-type udev-extension)))
- (description "This service adds udev rules."))))
- (service type #f)))
- (define (swap-space->shepherd-service-name space)
- (let ((target (swap-space-target space)))
- (symbol-append 'swap-
- (string->symbol
- (cond ((uuid? target)
- (uuid->string target))
- ((file-system-label? target)
- (file-system-label->string target))
- (else
- target))))))
- ; TODO Remove after deprecation
- (define (swap-deprecated->shepherd-service-name sdep)
- (symbol-append 'swap-
- (string->symbol
- (cond ((uuid? sdep)
- (string-take (uuid->string sdep) 6))
- ((file-system-label? sdep)
- (file-system-label->string sdep))
- (else
- sdep)))))
- (define swap->shepherd-service-name
- (match-lambda ((? swap-space? space)
- (swap-space->shepherd-service-name space))
- (sdep
- (swap-deprecated->shepherd-service-name sdep))))
- (define swap-service-type
- (shepherd-service-type
- 'swap
- (lambda (swap)
- (define requirements
- (cond ((swap-space? swap)
- (map dependency->shepherd-service-name
- (swap-space-dependencies swap)))
- ; TODO Remove after deprecation
- ((and (string? swap) (string-prefix? "/dev/mapper/" swap))
- (list (symbol-append 'device-mapping-
- (string->symbol (basename swap)))))
- (else
- '())))
- (define device-lookup
- ;; The generic 'find-partition' procedures could return a partition
- ;; that's not swap space, but that's unlikely.
- (cond ((swap-space? swap)
- (let ((target (swap-space-target swap)))
- (cond ((uuid? target)
- #~(find-partition-by-uuid #$(uuid-bytevector target)))
- ((file-system-label? target)
- #~(find-partition-by-label
- #$(file-system-label->string target)))
- (else
- target))))
- ; TODO Remove after deprecation
- ((uuid? swap)
- #~(find-partition-by-uuid #$(uuid-bytevector swap)))
- ((file-system-label? swap)
- #~(find-partition-by-label
- #$(file-system-label->string swap)))
- (else
- swap)))
- (with-imported-modules (source-module-closure '((gnu build file-systems)))
- (shepherd-service
- (provision (list (swap->shepherd-service-name swap)))
- (requirement `(udev ,@requirements))
- (documentation "Enable the given swap space.")
- (modules `((gnu build file-systems)
- ,@%default-modules))
- (start #~(lambda ()
- (let ((device #$device-lookup))
- (and device
- (begin
- (restart-on-EINTR (swapon device
- #$(if (swap-space? swap)
- (swap-space->flags-bit-mask
- swap)
- 0)))
- #t)))))
- (stop #~(lambda _
- (let ((device #$device-lookup))
- (when device
- (restart-on-EINTR (swapoff device)))
- #f)))
- (respawn? #f))))
- (description "Turn on the virtual memory swap area.")))
- (define (swap-service swap)
- "Return a service that uses @var{swap} as a swap space."
- (service swap-service-type swap))
- (define %default-gpm-options
- ;; Default options for GPM.
- '("-m" "/dev/input/mice" "-t" "ps2"))
- (define-record-type* <gpm-configuration>
- gpm-configuration make-gpm-configuration gpm-configuration?
- (gpm gpm-configuration-gpm ;file-like
- (default gpm))
- (options gpm-configuration-options ;list of strings
- (default %default-gpm-options)))
- (define (gpm-shepherd-service config)
- (match-record config <gpm-configuration>
- (gpm options)
- (list (shepherd-service
- (requirement '(udev))
- (provision '(gpm))
- ;; 'gpm' runs in the background and sets a PID file.
- ;; Note that it requires running as "root".
- (start #~(make-forkexec-constructor
- (list #$(file-append gpm "/sbin/gpm")
- #$@options)
- #:pid-file "/var/run/gpm.pid"
- #:pid-file-timeout 3))
- (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)))
- (default-value (gpm-configuration))
- (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-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")))
- (auto-login kmscon-configuration-auto-login
- (default #f))
- (hardware-acceleration? kmscon-configuration-hardware-acceleration?
- (default #f)) ; #t causes failure
- (font-engine kmscon-configuration-font-engine
- (default "pango"))
- (font-size kmscon-configuration-font-size
- (default 12))
- (keyboard-layout kmscon-configuration-keyboard-layout
- (default #f))) ; #f | <keyboard-layout>
- (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))
- (auto-login (kmscon-configuration-auto-login config))
- (hardware-acceleration? (kmscon-configuration-hardware-acceleration? config))
- (font-engine (kmscon-configuration-font-engine config))
- (font-size (kmscon-configuration-font-size config))
- (keyboard-layout (kmscon-configuration-keyboard-layout config)))
- (define kmscon-command
- #~(list
- #$(file-append kmscon "/bin/kmscon") "--login"
- "--vt" #$virtual-terminal
- "--no-switchvt" ;Prevent a switch to the virtual terminal.
- "--font-engine" #$font-engine
- "--font-size" #$(number->string font-size)
- #$@(if keyboard-layout
- (let* ((layout (keyboard-layout-name keyboard-layout))
- (variant (keyboard-layout-variant keyboard-layout))
- (model (keyboard-layout-model keyboard-layout))
- (options (keyboard-layout-options keyboard-layout)))
- `("--xkb-layout" ,layout
- ,@(if variant `("--xkb-variant" ,variant) '())
- ,@(if model `("--xkb-model" ,model) '())
- ,@(if (null? options)
- '()
- `("--xkb-options" ,(string-join options ",")))))
- '())
- #$@(if hardware-acceleration? '("--hwaccel") '())
- "--login" "--"
- #$login-program #$@login-arguments
- #$@(if auto-login
- #~(#$auto-login)
- #~())))
- (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
- ;; The installer needs to be able to display glyphs from
- ;; various scripts, so give it access to unifont.
- ;; TODO: Make this configurable.
- #:environment-variables
- (list (string-append "XDG_DATA_DIRS="
- #+font-gnu-unifont "/share"))))
- (stop #~(make-kill-destructor)))))
- (description "Start the @command{kmscon} virtual terminal emulator for the
- Linux @dfn{kernel mode setting} (KMS).")))
- ;;;
- ;;; Static networking.
- ;;;
- (define (ipv6-address? str)
- "Return true if STR denotes an IPv6 address."
- (false-if-exception (->bool (inet-pton AF_INET6 str))))
- (define-compile-time-procedure (assert-valid-address (address string?))
- "Ensure ADDRESS has a valid netmask."
- (unless (cidr->netmask address)
- (raise
- (make-compound-condition
- (formatted-message (G_ "address '~a' lacks a network mask")
- address)
- (condition (&error-location
- (location
- (source-properties->location procedure-call-location))))
- (condition (&fix-hint
- (hint (format #f (G_ "\
- Write, say, @samp{\"~a/24\"} for a 24-bit network mask.")
- address)))))))
- address)
- (define-record-type* <static-networking>
- static-networking make-static-networking
- static-networking?
- (addresses static-networking-addresses) ;list of <network-address>
- (links static-networking-links (default '())) ;list of <network-link>
- (routes static-networking-routes (default '())) ;list of <network-routes>
- (provision static-networking-provision
- (default '(networking)))
- (requirement static-networking-requirement
- (default '(udev)))
- (name-servers static-networking-name-servers ;FIXME: doesn't belong here
- (default '())))
- (define-record-type* <network-address>
- network-address make-network-address
- network-address?
- (device network-address-device) ;string--e.g., "en01"
- (value network-address-value ;string--CIDR notation
- (sanitize assert-valid-address))
- (ipv6? network-address-ipv6? ;Boolean
- (thunked)
- (default
- (ipv6-address? (cidr->ip (network-address-value this-record))))))
- (define-record-type* <network-link>
- network-link make-network-link
- network-link?
- (name network-link-name) ;string--e.g, "v0p0"
- (type network-link-type) ;symbol--e.g.,'veth
- (arguments network-link-arguments)) ;list
- (define-record-type* <network-route>
- network-route make-network-route
- network-route?
- (destination network-route-destination)
- (source network-route-source (default #f))
- (device network-route-device (default #f))
- (ipv6? network-route-ipv6? (thunked)
- (default
- (or (ipv6-address? (network-route-destination this-record))
- (and=> (network-route-gateway this-record)
- ipv6-address?))))
- (gateway network-route-gateway (default #f)))
- (eval-when (expand load eval)
- (define* (cidr->netmask str #:optional (family AF_INET))
- "Given @var{str}, a string in CIDR notation (e.g., \"1.2.3.4/24\"), return
- the netmask as a string like \"255.255.255.0\"."
- (match (string-split str #\/)
- ((ip (= string->number bits))
- (let ((mask (ash (- (expt 2 bits) 1)
- (- (if (= family AF_INET6) 128 32)
- bits))))
- (inet-ntop family mask)))
- (_ #f))))
- (define (cidr->ip str)
- "Strip the netmask bit of @var{str}, a CIDR-notation IP/netmask address."
- (match (string-split str #\/)
- ((or (ip _) (ip))
- ip)))
- (define* (ip+netmask->cidr ip netmask #:optional (family AF_INET))
- "Return the CIDR notation (a string) for @var{ip} and @var{netmask}, two
- @var{family} address strings, where @var{family} is @code{AF_INET} or
- @code{AF_INET6}."
- (let* ((netmask (inet-pton family netmask))
- (bits (logcount netmask)))
- (string-append ip "/" (number->string bits))))
- (define (static-networking->hurd-pfinet-options config)
- "Return command-line options for the Hurd's pfinet translator corresponding
- to CONFIG."
- (unless (null? (static-networking-links config))
- ;; XXX: Presumably this is not supported, or perhaps could be approximated
- ;; by running separate pfinet instances in some cases?
- (warning (G_ "network links are currently ignored on GNU/Hurd~%")))
- (match (static-networking-addresses config)
- ((and addresses (first _ ...))
- `("--ipv6" "/servers/socket/26"
- "--interface" ,(string-append "/dev/" (network-address-device first))
- ,@(append-map (lambda (address)
- `(,(if (network-address-ipv6? address)
- "--address6"
- "--address")
- ,(cidr->ip (network-address-value address))
- ,@(match (cidr->netmask (network-address-value address)
- (if (network-address-ipv6? address)
- AF_INET6
- AF_INET))
- (#f '())
- (mask (list "--netmask" mask)))))
- addresses)
- ,@(append-map (lambda (route)
- (match route
- (($ <network-route> "default" #f device _ gateway)
- (if (network-route-ipv6? route)
- `("--gateway6" ,gateway)
- `("--gateway" ,gateway)))
- (($ <network-route> destination)
- (warning (G_ "ignoring network route for '~a'~%")
- destination)
- '())))
- (static-networking-routes config))))))
- (define (network-set-up/hurd config)
- "Set up networking for the Hurd."
- ;; The Hurd implements SIOCGIFADDR and other old-style ioctls, but the only
- ;; way to set up IPv6 is by starting pfinet with the right options.
- (if (equal? (static-networking-provision config) '(loopback))
- (scheme-file "set-up-pflocal" #~(begin 'nothing-to-do! #t))
- (scheme-file "set-up-pfinet"
- (with-imported-modules '((guix build utils))
- #~(begin
- (use-modules (guix build utils)
- (ice-9 format))
- ;; TODO: Do that without forking.
- (let ((options '#$(static-networking->hurd-pfinet-options
- config)))
- (format #t "starting '~a~{ ~s~}'~%"
- #$(file-append hurd "/hurd/pfinet")
- options)
- (apply invoke #$(file-append hurd "/bin/settrans")
- "--active"
- "--create"
- "--keep-active"
- "/servers/socket/2"
- #$(file-append hurd "/hurd/pfinet")
- options)))))))
- (define (network-tear-down/hurd config)
- (scheme-file "tear-down-pfinet"
- (with-imported-modules '((guix build utils))
- #~(begin
- (use-modules (guix build utils))
- ;; Forcefully terminate pfinet. XXX: In theory this
- ;; should just undo the addresses and routes of CONFIG;
- ;; this could be done using ioctls like SIOCDELRT, but
- ;; these are IPv4-only; another option would be to use
- ;; fsysopts but that seems to crash pfinet.
- (invoke #$(file-append hurd "/bin/settrans") "-fg"
- "/servers/socket/2")
- #f))))
- (define (network-set-up/linux config)
- (match-record config <static-networking>
- (addresses links routes)
- (scheme-file "set-up-network"
- (with-extensions (list guile-netlink)
- #~(begin
- (use-modules (ip addr) (ip link) (ip route))
- #$@(map (lambda (address)
- #~(begin
- ;; Before going any further, wait for the
- ;; device to show up.
- (wait-for-link
- #$(network-address-device address)
- #:blocking? #f)
- (addr-add #$(network-address-device address)
- #$(network-address-value address)
- #:ipv6?
- #$(network-address-ipv6? address))
- ;; FIXME: loopback?
- (link-set #$(network-address-device address)
- #:multicast-on #t
- #:up #t)))
- addresses)
- #$@(map (match-lambda
- (($ <network-link> name type arguments)
- #~(link-add #$name #$type
- #:type-args '#$arguments)))
- links)
- #$@(map (lambda (route)
- #~(route-add #$(network-route-destination route)
- #:device
- #$(network-route-device route)
- #:ipv6?
- #$(network-route-ipv6? route)
- #:via
- #$(network-route-gateway route)
- #:src
- #$(network-route-source route)))
- routes)
- #t)))))
- (define (network-tear-down/linux config)
- (match-record config <static-networking>
- (addresses links routes)
- (scheme-file "tear-down-network"
- (with-extensions (list guile-netlink)
- #~(begin
- (use-modules (ip addr) (ip link) (ip route)
- (netlink error)
- (srfi srfi-34))
- (define-syntax-rule (false-if-netlink-error exp)
- (guard (c ((netlink-error? c) #f))
- exp))
- ;; Wrap calls in 'false-if-netlink-error' so this
- ;; script goes as far as possible undoing the effects
- ;; of "set-up-network".
- #$@(map (lambda (route)
- #~(false-if-netlink-error
- (route-del #$(network-route-destination route)
- #:device
- #$(network-route-device route)
- #:ipv6?
- #$(network-route-ipv6? route)
- #:via
- #$(network-route-gateway route)
- #:src
- #$(network-route-source route))))
- routes)
- #$@(map (match-lambda
- (($ <network-link> name type arguments)
- #~(false-if-netlink-error
- (link-del #$name))))
- links)
- #$@(map (lambda (address)
- #~(false-if-netlink-error
- (addr-del #$(network-address-device
- address)
- #$(network-address-value address)
- #:ipv6?
- #$(network-address-ipv6? address))))
- addresses)
- #f)))))
- (define (static-networking-shepherd-service config)
- (match-record config <static-networking>
- (addresses links routes provision requirement name-servers)
- (let ((loopback? (and provision (memq 'loopback provision))))
- (shepherd-service
- (documentation
- "Bring up the networking interface using a static IP address.")
- (requirement requirement)
- (provision provision)
- (start #~(lambda _
- ;; Return #t if successfully started.
- (load #$(let-system (system target)
- (if (string-contains (or target system) "-linux")
- (network-set-up/linux config)
- (network-set-up/hurd config))))))
- (stop #~(lambda _
- ;; Return #f is successfully stopped.
- (load #$(let-system (system target)
- (if (string-contains (or target system) "-linux")
- (network-tear-down/linux config)
- (network-tear-down/hurd config))))))
- (respawn? #f)))))
- (define (static-networking-shepherd-services networks)
- (map static-networking-shepherd-service networks))
- (define (static-networking-etc-files interfaces)
- "Return a /etc/resolv.conf entry for INTERFACES or the empty list."
- (match (delete-duplicates
- (append-map static-networking-name-servers
- interfaces))
- (()
- '())
- ((name-servers ...)
- (let ((content (string-join
- (map (cut string-append "nameserver " <>)
- name-servers)
- "\n" 'suffix)))
- `(("resolv.conf"
- ,(plain-file "resolv.conf"
- (string-append "\
- # Generated by 'static-networking-service'.\n"
- content))))))))
- (define static-networking-service-type
- ;; The service type for statically-defined network interfaces.
- (service-type (name 'static-networking)
- (extensions
- (list
- (service-extension shepherd-root-service-type
- static-networking-shepherd-services)
- (service-extension etc-service-type
- static-networking-etc-files)))
- (compose concatenate)
- (extend append)
- (description
- "Turn up the specified network interfaces upon startup,
- with the given IP address, gateway, netmask, and so on. The value for
- services of this type is a list of @code{static-networking} objects, one per
- network interface.")))
- (define-deprecated (static-networking-service interface ip
- #:key
- netmask gateway provision
- ;; Most interfaces require udev to be usable.
- (requirement '(udev))
- (name-servers '()))
- static-networking-service-type
- "Return a service that starts @var{interface} with address @var{ip}. If
- @var{netmask} is true, use it as the network mask. If @var{gateway} is true,
- it must be a string specifying the default network gateway.
- This procedure can be called several times, one for each network
- interface of interest. Behind the scenes what it does is extend
- @code{static-networking-service-type} with additional network interfaces
- to handle."
- (simple-service 'static-network-interface
- static-networking-service-type
- (list (static-networking
- (addresses
- (list (network-address
- (device interface)
- (value (if netmask
- (ip+netmask->cidr ip netmask)
- ip))
- (ipv6? #f))))
- (routes
- (if gateway
- (list (network-route
- (destination "default")
- (gateway gateway)
- (ipv6? #f)))
- '()))
- (requirement requirement)
- (provision (or provision '(networking)))
- (name-servers name-servers)))))
- (define %loopback-static-networking
- ;; The loopback device.
- (static-networking
- (addresses (list (network-address
- (device "lo")
- (value "127.0.0.1/8"))))
- (requirement '())
- (provision '(loopback))))
- (define %qemu-static-networking
- ;; Networking configuration for QEMU's user-mode network stack (info "(QEMU)
- ;; Using the user mode network stack").
- (static-networking
- (addresses (list (network-address
- (device "eth0")
- (value "10.0.2.15/24"))))
- (routes (list (network-route
- (destination "default")
- (gateway "10.0.2.2"))))
- (requirement '())
- (provision '(networking))
- (name-servers '("10.0.2.3"))))
- ;;;
- ;;; greetd-service-type -- minimal and flexible login manager daemon
- ;;;
- (define-record-type* <greetd-agreety-session>
- greetd-agreety-session make-greetd-agreety-session
- greetd-agreety-session?
- (agreety greetd-agreety (default greetd))
- (command greetd-agreety-command (default (file-append bash "/bin/bash")))
- (command-args greetd-agreety-command-args (default '("-l")))
- (extra-env greetd-agreety-extra-env (default '()))
- (xdg-env? greetd-agreety-xdg-env? (default #t)))
- (define (greetd-agreety-tty-session-command config)
- (match-record config <greetd-agreety-session>
- (command command-args extra-env)
- (program-file
- "agreety-tty-session-command"
- #~(begin
- (use-modules (ice-9 match))
- (for-each (match-lambda ((var . val) (setenv var val)))
- (quote (#$@extra-env)))
- (apply execl #$command #$command (list #$@command-args))))))
- (define (greetd-agreety-tty-xdg-session-command config)
- (match-record config <greetd-agreety-session>
- (command command-args extra-env)
- (program-file
- "agreety-tty-xdg-session-command"
- #~(begin
- (use-modules (ice-9 match))
- (let*
- ((username (getenv "USER"))
- (useruid (passwd:uid (getpwuid username)))
- (useruid (number->string useruid)))
- (setenv "XDG_SESSION_TYPE" "tty")
- (setenv "XDG_RUNTIME_DIR" (string-append "/run/user/" useruid)))
- (for-each (match-lambda ((var . val) (setenv var val)))
- (quote (#$@extra-env)))
- (apply execl #$command #$command (list #$@command-args))))))
- (define-gexp-compiler (greetd-agreety-session-compiler
- (session <greetd-agreety-session>)
- system target)
- (let ((agreety (file-append (greetd-agreety session)
- "/bin/agreety"))
- (command ((if (greetd-agreety-xdg-env? session)
- greetd-agreety-tty-xdg-session-command
- greetd-agreety-tty-session-command)
- session)))
- (lower-object
- (program-file "agreety-command"
- #~(execl #$agreety #$agreety "-c" #$command)))))
- (define-record-type* <greetd-wlgreet-session>
- greetd-wlgreet-session make-greetd-wlgreet-session
- greetd-wlgreet-session?
- (wlgreet greetd-wlgreet (default wlgreet))
- (command greetd-wlgreet-command
- (default (file-append sway "/bin/sway")))
- (command-args greetd-wlgreet-command-args (default '()))
- (output-mode greetd-wlgreet-output-mode (default "all"))
- (scale greetd-wlgreet-scale (default 1))
- (background greetd-wlgreet-background (default '(0 0 0 0.9)))
- (headline greetd-wlgreet-headline (default '(1 1 1 1)))
- (prompt greetd-wlgreet-prompt (default '(1 1 1 1)))
- (prompt-error greetd-wlgreet-prompt-error (default '(1 1 1 1)))
- (border greetd-wlgreet-border (default '(1 1 1 1)))
- (extra-env greetd-wlgreet-extra-env (default '())))
- (define (greetd-wlgreet-wayland-session-command session)
- (program-file "wlgreet-session-command"
- #~(let* ((username (getenv "USER"))
- (useruid (number->string
- (passwd:uid (getpwuid username))))
- (command #$(greetd-wlgreet-command session)))
- (use-modules (ice-9 match))
- (setenv "XDG_SESSION_TYPE" "wayland")
- (setenv "XDG_RUNTIME_DIR" (string-append "/run/user/" useruid))
- (for-each (lambda (env) (setenv (car env) (cdr env)))
- '(#$@(greetd-wlgreet-extra-env session)))
- (apply execl command command
- (list #$@(greetd-wlgreet-command-args session))))))
- (define (make-wlgreet-config-color section-name color)
- (match color
- ((red green blue opacity)
- (string-append
- "[" section-name "]\n"
- "red = " (number->string red) "\n"
- "green = " (number->string green) "\n"
- "blue = " (number->string blue) "\n"
- "opacity = " (number->string opacity) "\n"))))
- (define (make-wlgreet-configuration-file session)
- (let ((command (greetd-wlgreet-wayland-session-command session))
- (output-mode (greetd-wlgreet-output-mode session))
- (scale (greetd-wlgreet-scale session))
- (background (greetd-wlgreet-background session))
- (headline (greetd-wlgreet-headline session))
- (prompt (greetd-wlgreet-prompt session))
- (prompt-error (greetd-wlgreet-prompt-error session))
- (border (greetd-wlgreet-border session)))
- (mixed-text-file "wlgreet.toml"
- "command = \"" command "\"\n"
- "outputMode = \"" output-mode "\"\n"
- "scale = " (number->string scale) "\n"
- (apply string-append
- (map (match-lambda
- ((section-name . color)
- (make-wlgreet-config-color section-name color)))
- `(("background" . ,background)
- ("headline" . ,headline)
- ("prompt" . ,prompt)
- ("prompt-error" . ,prompt-error)
- ("border" . ,border)))))))
- (define-record-type* <greetd-wlgreet-sway-session>
- greetd-wlgreet-sway-session make-greetd-wlgreet-sway-session
- greetd-wlgreet-sway-session?
- (wlgreet-session greetd-wlgreet-sway-session-wlgreet-session ;<greetd-wlgreet-session>
- (default (greetd-wlgreet-session)))
- (sway greetd-wlgreet-sway-session-sway (default sway)) ;<package>
- (sway-configuration greetd-wlgreet-sway-session-sway-configuration ;file-like
- (default (plain-file "wlgreet-sway-config" ""))))
- (define (make-wlgreet-sway-configuration-file session)
- (let* ((wlgreet-session (greetd-wlgreet-sway-session-wlgreet-session session))
- (wlgreet-config (make-wlgreet-configuration-file wlgreet-session))
- (wlgreet (file-append (greetd-wlgreet wlgreet-session) "/bin/wlgreet"))
- (sway-config (greetd-wlgreet-sway-session-sway-configuration session))
- (swaymsg (file-append (greetd-wlgreet-sway-session-sway session)
- "/bin/swaymsg")))
- (mixed-text-file "wlgreet-sway.conf"
- "include " sway-config "\n"
- "xwayland disable\n"
- "exec \"" wlgreet " --config " wlgreet-config "; "
- swaymsg " exit\"\n")))
- (define-gexp-compiler (greetd-wlgreet-sway-session-compiler
- (session <greetd-wlgreet-sway-session>)
- system target)
- (let ((sway (file-append (greetd-wlgreet-sway-session-sway session)
- "/bin/sway"))
- (config (make-wlgreet-sway-configuration-file session)))
- (lower-object
- (program-file "wlgreet-sway-session-command"
- #~(let* ((log-file (open-output-file
- (string-append "/tmp/sway-greeter."
- (number->string (getpid))
- ".log")))
- (username (getenv "USER"))
- (useruid (number->string (passwd:uid (getpwuid username)))))
- ;; redirect stdout/err to log-file
- (dup2 (fileno log-file) 1)
- (dup2 1 2)
- (sleep 1) ;give seatd/logind some time to start up
- (setenv "XDG_RUNTIME_DIR" (string-append "/run/user/" useruid))
- (execl #$sway #$sway "-d" "-c" #$config))))))
- (define-record-type* <greetd-terminal-configuration>
- greetd-terminal-configuration make-greetd-terminal-configuration
- greetd-terminal-configuration?
- (greetd greetd-package (default greetd))
- (config-file-name greetd-config-file-name (thunked)
- (default (default-config-file-name this-record)))
- (log-file-name greetd-log-file-name (thunked)
- (default (default-log-file-name this-record)))
- (terminal-vt greetd-terminal-vt (default "7"))
- (terminal-switch greetd-terminal-switch (default #f))
- (source-profile? greetd-source-profile? (default #t))
- (default-session-user greetd-default-session-user (default "greeter"))
- (default-session-command greetd-default-session-command
- (default (greetd-agreety-session))))
- (define (default-config-file-name config)
- (string-join (list "config-" (greetd-terminal-vt config) ".toml") ""))
- (define (default-log-file-name config)
- (string-join (list "/var/log/greetd-" (greetd-terminal-vt config) ".log") ""))
- (define (make-greetd-terminal-configuration-file config)
- (let*
- ((config-file-name (greetd-config-file-name config))
- (source-profile? (greetd-source-profile? config))
- (terminal-vt (greetd-terminal-vt config))
- (terminal-switch (greetd-terminal-switch config))
- (default-session-user (greetd-default-session-user config))
- (default-session-command (greetd-default-session-command config)))
- (mixed-text-file
- config-file-name
- "[general]\n"
- "source_profile = " (if source-profile? "true" "false") "\n"
- "[terminal]\n"
- "vt = " terminal-vt "\n"
- "switch = " (if terminal-switch "true" "false") "\n"
- "[default_session]\n"
- "user = " default-session-user "\n"
- "command = " default-session-command "\n")))
- (define %greetd-file-systems
- (list (file-system
- (device "none")
- (mount-point "/run/greetd/pam_mount")
- (type "tmpfs")
- (check? #f)
- (flags '(no-suid no-dev no-exec))
- (options "mode=0755")
- (create-mount-point? #t))))
- (define %greetd-pam-mount-rules
- `((debug (@ (enable "0")))
- (volume (@ (sgrp "users")
- (fstype "tmpfs")
- (mountpoint "/run/user/%(USERUID)")
- (options "noexec,nosuid,nodev,size=1g,mode=0700,uid=%(USERUID),gid=%(USERGID)")))
- (logout (@ (wait "0")
- (hup "0")
- (term "yes")
- (kill "no")))
- (mkmountpoint (@ (enable "1") (remove "true")))))
- (define-record-type* <greetd-configuration>
- greetd-configuration make-greetd-configuration
- greetd-configuration?
- (motd greetd-motd (default %default-motd))
- (allow-empty-passwords? greetd-allow-empty-passwords? (default #t))
- (terminals greetd-terminals (default '()))
- (greeter-supplementary-groups greetd-greeter-supplementary-groups (default '())))
- (define (greetd-accounts config)
- (list (user-group (name "greeter") (system? #t))
- (user-account
- (name "greeter")
- (group "greeter")
- (supplementary-groups (greetd-greeter-supplementary-groups config))
- (system? #t))))
- (define (make-greetd-pam-mount-conf-file config)
- (computed-file
- "greetd_pam_mount.conf.xml"
- #~(begin
- (use-modules (sxml simple))
- (call-with-output-file #$output
- (lambda (port)
- (sxml->xml
- '(*TOP*
- (*PI* xml "version='1.0' encoding='utf-8'")
- (pam_mount
- #$@%greetd-pam-mount-rules
- (pmvarrun
- #$(file-append greetd-pam-mount
- "/sbin/pmvarrun -u '%(USER)' -o '%(OPERATION)'"))))
- port))))))
- (define (greetd-etc-service config)
- `(("security/greetd_pam_mount.conf.xml"
- ,(make-greetd-pam-mount-conf-file config))))
- (define (greetd-pam-service config)
- (define optional-pam-mount
- (pam-entry
- (control "optional")
- (module (file-append greetd-pam-mount "/lib/security/pam_mount.so"))
- (arguments '("disable_interactive"))))
- (list
- (unix-pam-service "greetd"
- #:login-uid? #t
- #:allow-empty-passwords?
- (greetd-allow-empty-passwords? config)
- #:motd
- (greetd-motd config))
- (pam-extension
- (transformer
- (lambda (pam)
- (if (member (pam-service-name pam)
- '("login" "greetd" "su" "slim" "gdm-password"))
- (pam-service
- (inherit pam)
- (auth (append (pam-service-auth pam)
- (list optional-pam-mount)))
- (session (append (pam-service-session pam)
- (list optional-pam-mount))))
- pam))))))
- (define (greetd-shepherd-services config)
- (map
- (lambda (tc)
- (let*
- ((greetd-bin (file-append (greetd-package tc) "/sbin/greetd"))
- (greetd-conf (make-greetd-terminal-configuration-file tc))
- (greetd-log (greetd-log-file-name tc))
- (greetd-vt (greetd-terminal-vt tc)))
- (shepherd-service
- (documentation "Minimal and flexible login manager daemon")
- (requirement '(pam user-processes host-name udev virtual-terminal))
- (provision (list (symbol-append
- 'term-tty
- (string->symbol (greetd-terminal-vt tc)))))
- (start #~(make-forkexec-constructor
- (list #$greetd-bin "-c" #$greetd-conf)
- #:log-file #$greetd-log))
- (stop #~(make-kill-destructor)))))
- (greetd-terminals config)))
- (define greetd-service-type
- (service-type
- (name 'greetd)
- (description "Provides necessary infrastructure for logging into the
- system including @code{greetd} PAM service, @code{pam-mount} module to
- mount/unmount /run/user/<uid> directory for user and @code{greetd}
- login manager daemon.")
- (extensions
- (list
- (service-extension account-service-type greetd-accounts)
- (service-extension file-system-service-type (const %greetd-file-systems))
- (service-extension etc-service-type greetd-etc-service)
- (service-extension pam-root-service-type greetd-pam-service)
- (service-extension shepherd-root-service-type greetd-shepherd-services)))
- (default-value (greetd-configuration))))
- (define %base-services
- ;; Convenience variable holding the basic services.
- (list (service login-service-type)
- (service virtual-terminal-service-type)
- (service console-font-service-type
- (map (lambda (tty)
- (cons tty %default-console-font))
- '("tty1" "tty2" "tty3" "tty4" "tty5" "tty6")))
- (service syslog-service-type)
- (service agetty-service-type (agetty-configuration
- (extra-options '("-L")) ; no carrier detect
- (term "vt100")
- (tty #f) ; automatic
- (shepherd-requirement '(syslogd))))
- (service mingetty-service-type (mingetty-configuration
- (tty "tty1")))
- (service mingetty-service-type (mingetty-configuration
- (tty "tty2")))
- (service mingetty-service-type (mingetty-configuration
- (tty "tty3")))
- (service mingetty-service-type (mingetty-configuration
- (tty "tty4")))
- (service mingetty-service-type (mingetty-configuration
- (tty "tty5")))
- (service mingetty-service-type (mingetty-configuration
- (tty "tty6")))
- (service static-networking-service-type
- (list %loopback-static-networking))
- (service urandom-seed-service-type)
- (service guix-service-type)
- (service nscd-service-type)
- (service rottlog-service-type)
- ;; Periodically delete old build logs.
- (service log-cleanup-service-type
- (log-cleanup-configuration
- (directory "/var/log/guix/drvs")))
- ;; 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.
- (service udev-service-type
- (udev-configuration
- (rules (list lvm2 fuse alsa-utils crda))))
- (service sysctl-service-type)
- (service special-files-service-type
- `(("/bin/sh" ,(file-append bash "/bin/sh"))
- ("/usr/bin/env" ,(file-append coreutils "/bin/env"))))))
- ;;; base.scm ends here
|