services.scm 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
  4. ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  5. ;;; Copyright © 2020, 2021 Ricardo Wurmus <rekado@elephly.net>
  6. ;;; Copyright © 2021 raid5atemyhomework <raid5atemyhomework@protonmail.com>
  7. ;;;
  8. ;;; This file is part of GNU Guix.
  9. ;;;
  10. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  11. ;;; under the terms of the GNU General Public License as published by
  12. ;;; the Free Software Foundation; either version 3 of the License, or (at
  13. ;;; your option) any later version.
  14. ;;;
  15. ;;; GNU Guix is distributed in the hope that it will be useful, but
  16. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;;; GNU General Public License for more details.
  19. ;;;
  20. ;;; You should have received a copy of the GNU General Public License
  21. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  22. (define-module (gnu services)
  23. #:use-module (guix gexp)
  24. #:use-module (guix monads)
  25. #:use-module (guix store)
  26. #:use-module (guix records)
  27. #:use-module (guix profiles)
  28. #:use-module (guix discovery)
  29. #:use-module (guix combinators)
  30. #:use-module (guix channels)
  31. #:use-module (guix describe)
  32. #:use-module (guix sets)
  33. #:use-module (guix ui)
  34. #:use-module (guix diagnostics)
  35. #:autoload (guix openpgp) (openpgp-format-fingerprint)
  36. #:use-module (guix modules)
  37. #:use-module (guix packages)
  38. #:use-module (guix utils)
  39. #:use-module (gnu packages base)
  40. #:use-module (gnu packages bash)
  41. #:use-module (gnu packages hurd)
  42. #:use-module (srfi srfi-1)
  43. #:use-module (srfi srfi-9)
  44. #:use-module (srfi srfi-9 gnu)
  45. #:use-module (srfi srfi-26)
  46. #:use-module (srfi srfi-34)
  47. #:use-module (srfi srfi-35)
  48. #:use-module (ice-9 vlist)
  49. #:use-module (ice-9 match)
  50. #:autoload (ice-9 pretty-print) (pretty-print)
  51. #:export (service-extension
  52. service-extension?
  53. service-extension-target
  54. service-extension-compute
  55. service-type
  56. service-type?
  57. service-type-name
  58. service-type-extensions
  59. service-type-compose
  60. service-type-extend
  61. service-type-default-value
  62. service-type-description
  63. service-type-location
  64. %service-type-path
  65. fold-service-types
  66. lookup-service-types
  67. service
  68. service?
  69. service-kind
  70. service-value
  71. service-parameters ;deprecated
  72. simple-service
  73. modify-services
  74. service-back-edges
  75. instantiate-missing-services
  76. fold-services
  77. service-error?
  78. missing-value-service-error?
  79. missing-value-service-error-type
  80. missing-value-service-error-location
  81. missing-target-service-error?
  82. missing-target-service-error-service
  83. missing-target-service-error-target-type
  84. ambiguous-target-service-error?
  85. ambiguous-target-service-error-service
  86. ambiguous-target-service-error-target-type
  87. system-service-type
  88. provenance-service-type
  89. sexp->system-provenance
  90. system-provenance
  91. boot-service-type
  92. cleanup-service-type
  93. activation-service-type
  94. activation-service->script
  95. %linux-bare-metal-service
  96. %hurd-rc-script
  97. %hurd-startup-service
  98. special-files-service-type
  99. extra-special-file
  100. etc-service-type
  101. etc-directory
  102. setuid-program-service-type
  103. profile-service-type
  104. firmware-service-type
  105. gc-root-service-type
  106. linux-builder-service-type
  107. linux-builder-configuration
  108. linux-builder-configuration?
  109. linux-builder-configuration-kernel
  110. linux-builder-configuration-modules
  111. linux-loadable-module-service-type
  112. %boot-service
  113. %activation-service
  114. etc-service)
  115. #:re-export (;; Note: Re-export 'delete' to allow for proper syntax matching
  116. ;; in 'modify-services' forms. See
  117. ;; <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=26805#16>.
  118. delete))
  119. ;;; Comment:
  120. ;;;
  121. ;;; This module defines a broad notion of "service types" and "services."
  122. ;;;
  123. ;;; A service type describe how its instances extend instances of other
  124. ;;; service types. For instance, some services extend the instance of
  125. ;;; ACCOUNT-SERVICE-TYPE by providing it with accounts and groups to create;
  126. ;;; others extend SHEPHERD-ROOT-SERVICE-TYPE by passing it instances of
  127. ;;; <shepherd-service>.
  128. ;;;
  129. ;;; When applicable, the service type defines how it can itself be extended,
  130. ;;; by providing one procedure to compose extensions, and one procedure to
  131. ;;; extend itself.
  132. ;;;
  133. ;;; A notable service type is SYSTEM-SERVICE-TYPE, which has a single
  134. ;;; instance, which is the root of the service DAG. Its value is the
  135. ;;; derivation that produces the 'system' directory as returned by
  136. ;;; 'operating-system-derivation'.
  137. ;;;
  138. ;;; The 'fold-services' procedure can be passed a list of procedures, which it
  139. ;;; "folds" by propagating extensions down the graph; it returns the root
  140. ;;; service after the applying all its extensions.
  141. ;;;
  142. ;;; Code:
  143. (define-record-type <service-extension>
  144. (service-extension target compute)
  145. service-extension?
  146. (target service-extension-target) ;<service-type>
  147. (compute service-extension-compute)) ;params -> params
  148. (define &no-default-value
  149. ;; Value used to denote service types that have no associated default value.
  150. '(no default value))
  151. (define-record-type* <service-type> service-type make-service-type
  152. service-type?
  153. (name service-type-name) ;symbol (for debugging)
  154. ;; Things extended by services of this type.
  155. (extensions service-type-extensions) ;list of <service-extensions>
  156. ;; Given a list of extensions, "compose" them.
  157. (compose service-type-compose ;list of Any -> Any
  158. (default #f))
  159. ;; Extend the services' own parameters with the extension composition.
  160. (extend service-type-extend ;list of Any -> parameters
  161. (default #f))
  162. ;; Optional default value for instances of this type.
  163. (default-value service-type-default-value ;Any
  164. (default &no-default-value))
  165. ;; Meta-data.
  166. (description service-type-description ;string
  167. (default #f))
  168. (location service-type-location ;<location>
  169. (default (and=> (current-source-location)
  170. source-properties->location))
  171. (innate)))
  172. (define (write-service-type type port)
  173. (format port "#<service-type ~a ~a>"
  174. (service-type-name type)
  175. (number->string (object-address type) 16)))
  176. (set-record-type-printer! <service-type> write-service-type)
  177. (define %distro-root-directory
  178. ;; Absolute file name of the module hierarchy.
  179. (dirname (search-path %load-path "guix.scm")))
  180. (define %service-type-path
  181. ;; Search path for service types.
  182. (make-parameter `((,%distro-root-directory . "gnu/services")
  183. (,%distro-root-directory . "gnu/system"))))
  184. (define (all-service-modules)
  185. "Return the default set of service modules."
  186. (cons (resolve-interface '(gnu services))
  187. (all-modules (%service-type-path)
  188. #:warn warn-about-load-error)))
  189. (define* (fold-service-types proc seed
  190. #:optional
  191. (modules (all-service-modules)))
  192. "For each service type exported by one of MODULES, call (PROC RESULT). SEED
  193. is used as the initial value of RESULT."
  194. (fold-module-public-variables (lambda (object result)
  195. (if (service-type? object)
  196. (proc object result)
  197. result))
  198. seed
  199. modules))
  200. (define lookup-service-types
  201. (let ((table
  202. (delay (fold-service-types (lambda (type result)
  203. (vhash-consq (service-type-name type)
  204. type result))
  205. vlist-null))))
  206. (lambda (name)
  207. "Return the list of services with the given NAME (a symbol)."
  208. (vhash-foldq* cons '() name (force table)))))
  209. ;; Services of a given type.
  210. (define-record-type <service>
  211. (make-service type value)
  212. service?
  213. (type service-kind)
  214. (value service-value))
  215. (define-syntax service
  216. (syntax-rules ()
  217. "Return a service instance of TYPE. The service value is VALUE or, if
  218. omitted, TYPE's default value."
  219. ((_ type value)
  220. (make-service type value))
  221. ((_ type)
  222. (%service-with-default-value (current-source-location)
  223. type))))
  224. (define (%service-with-default-value location type)
  225. "Return a instance of service type TYPE with its default value, if any. If
  226. TYPE does not have a default value, an error is raised."
  227. ;; TODO: Currently this is a run-time error but with a little bit macrology
  228. ;; we could turn it into an expansion-time error.
  229. (let ((default (service-type-default-value type)))
  230. (if (eq? default &no-default-value)
  231. (let ((location (source-properties->location location)))
  232. (raise
  233. (make-compound-condition
  234. (condition
  235. (&missing-value-service-error (type type) (location location)))
  236. (formatted-message (G_ "~a: no value specified \
  237. for service of type '~a'")
  238. (location->string location)
  239. (service-type-name type)))))
  240. (service type default))))
  241. (define-condition-type &service-error &error
  242. service-error?)
  243. (define-condition-type &missing-value-service-error &service-error
  244. missing-value-service-error?
  245. (type missing-value-service-error-type)
  246. (location missing-value-service-error-location))
  247. ;;;
  248. ;;; Helpers.
  249. ;;;
  250. (define service-parameters
  251. ;; Deprecated alias.
  252. service-value)
  253. (define (simple-service name target value)
  254. "Return a service that extends TARGET with VALUE. This works by creating a
  255. singleton service type NAME, of which the returned service is an instance."
  256. (let* ((extension (service-extension target identity))
  257. (type (service-type (name name)
  258. (extensions (list extension)))))
  259. (service type value)))
  260. (define-syntax %modify-service
  261. (syntax-rules (=> delete)
  262. ((_ svc (delete kind) clauses ...)
  263. (if (eq? (service-kind svc) kind)
  264. #f
  265. (%modify-service svc clauses ...)))
  266. ((_ service)
  267. service)
  268. ((_ svc (kind param => exp ...) clauses ...)
  269. (if (eq? (service-kind svc) kind)
  270. (let ((param (service-value svc)))
  271. (service (service-kind svc)
  272. (begin exp ...)))
  273. (%modify-service svc clauses ...)))))
  274. (define-syntax modify-services
  275. (syntax-rules ()
  276. "Modify the services listed in SERVICES according to CLAUSES and return
  277. the resulting list of services. Each clause must have the form:
  278. (TYPE VARIABLE => BODY)
  279. where TYPE is a service type, such as 'guix-service-type', and VARIABLE is an
  280. identifier that is bound within BODY to the value of the service of that
  281. TYPE. Consider this example:
  282. (modify-services %base-services
  283. (guix-service-type config =>
  284. (guix-configuration
  285. (inherit config)
  286. (use-substitutes? #f)
  287. (extra-options '(\"--gc-keep-derivations\"))))
  288. (mingetty-service-type config =>
  289. (mingetty-configuration
  290. (inherit config)
  291. (motd (plain-file \"motd\" \"Hi there!\"))))
  292. (delete udev-service-type))
  293. It changes the configuration of the GUIX-SERVICE-TYPE instance, and that of
  294. all the MINGETTY-SERVICE-TYPE instances, and it deletes instances of the
  295. UDEV-SERVICE-TYPE.
  296. This is a shorthand for (filter-map (lambda (svc) ...) %base-services)."
  297. ((_ services clauses ...)
  298. (filter-map (lambda (service)
  299. (%modify-service service clauses ...))
  300. services))))
  301. ;;;
  302. ;;; Core services.
  303. ;;;
  304. (define (system-derivation entries mextensions)
  305. "Return as a monadic value the derivation of the 'system' directory
  306. containing the given entries."
  307. (mlet %store-monad ((extensions (mapm/accumulate-builds identity
  308. mextensions)))
  309. (lower-object
  310. (file-union "system"
  311. (append entries (concatenate extensions))))))
  312. (define system-service-type
  313. ;; This is the ultimate service type, the root of the service DAG. The
  314. ;; service of this type is extended by monadic name/item pairs. These items
  315. ;; end up in the "system directory" as returned by
  316. ;; 'operating-system-derivation'.
  317. (service-type (name 'system)
  318. (extensions '())
  319. (compose identity)
  320. (extend system-derivation)
  321. (description
  322. "Build the operating system top-level directory, which in
  323. turn refers to everything the operating system needs: its kernel, initrd,
  324. system profile, boot script, and so on.")))
  325. (define (compute-boot-script _ gexps)
  326. ;; Reverse GEXPS so that extensions appear in the boot script in the right
  327. ;; order. That is, user extensions would come first, and extensions added
  328. ;; by 'essential-services' (e.g., running shepherd) are guaranteed to come
  329. ;; last.
  330. (gexp->file "boot"
  331. ;; Clean up and activate the system, then spawn shepherd.
  332. #~(begin #$@(reverse gexps))))
  333. (define (boot-script-entry mboot)
  334. "Return, as a monadic value, an entry for the boot script in the system
  335. directory."
  336. (mlet %store-monad ((boot mboot))
  337. (return `(("boot" ,boot)))))
  338. (define boot-service-type
  339. ;; The service of this type is extended by being passed gexps. It
  340. ;; aggregates them in a single script, as a monadic value, which becomes its
  341. ;; value.
  342. (service-type (name 'boot)
  343. (extensions
  344. (list (service-extension system-service-type
  345. boot-script-entry)))
  346. (compose identity)
  347. (extend compute-boot-script)
  348. (description
  349. "Produce the operating system's boot script, which is spawned
  350. by the initrd once the root file system is mounted.")))
  351. (define %boot-service
  352. ;; The service that produces the boot script.
  353. (service boot-service-type #t))
  354. ;;;
  355. ;;; Provenance tracking.
  356. ;;;
  357. (define (object->pretty-string obj)
  358. "Like 'object->string', but using 'pretty-print'."
  359. (call-with-output-string
  360. (lambda (port)
  361. (pretty-print obj port))))
  362. (define (channel->code channel)
  363. "Return code to build CHANNEL, ready to be dropped in a 'channels.scm'
  364. file."
  365. ;; Since the 'introduction' field is backward-incompatible, and since it's
  366. ;; optional when using the "official" 'guix channel, include it if and only
  367. ;; if we're referring to a different channel.
  368. (let ((intro (and (not (equal? (list channel) %default-channels))
  369. (channel-introduction channel))))
  370. `(channel (name ',(channel-name channel))
  371. (url ,(channel-url channel))
  372. (branch ,(channel-branch channel))
  373. (commit ,(channel-commit channel))
  374. ,@(if intro
  375. `((introduction
  376. (make-channel-introduction
  377. ,(channel-introduction-first-signed-commit intro)
  378. (openpgp-fingerprint
  379. ,(openpgp-format-fingerprint
  380. (channel-introduction-first-commit-signer
  381. intro))))))
  382. '()))))
  383. (define (channel->sexp channel)
  384. "Return an sexp describing CHANNEL. The sexp is _not_ code and is meant to
  385. be parsed by tools; it's potentially more future-proof than code."
  386. ;; TODO: Add CHANNEL's introduction. Currently we can't do that because
  387. ;; older 'guix system describe' expect exactly name/url/branch/commit
  388. ;; without any additional fields.
  389. `(channel (name ,(channel-name channel))
  390. (url ,(channel-url channel))
  391. (branch ,(channel-branch channel))
  392. (commit ,(channel-commit channel))))
  393. (define (sexp->channel sexp)
  394. "Return the channel corresponding to SEXP, an sexp as found in the
  395. \"provenance\" file produced by 'provenance-service-type'."
  396. (match sexp
  397. (('channel ('name name)
  398. ('url url)
  399. ('branch branch)
  400. ('commit commit)
  401. rest ...)
  402. ;; XXX: In the future REST may include a channel introduction.
  403. (channel (name name) (url url)
  404. (branch branch) (commit commit)))))
  405. (define (provenance-file channels config-file)
  406. "Return a 'provenance' file describing CHANNELS, a list of channels, and
  407. CONFIG-FILE, which can be either #f or a <local-file> containing the OS
  408. configuration being used."
  409. (scheme-file "provenance"
  410. #~(provenance
  411. (version 0)
  412. (channels #+@(if channels
  413. (map channel->sexp channels)
  414. '()))
  415. (configuration-file #+config-file))))
  416. (define (provenance-entry config-file)
  417. "Return system entries describing the operating system provenance: the
  418. channels in use and CONFIG-FILE, if it is true."
  419. (define profile
  420. (current-profile))
  421. (define channels
  422. (and=> profile profile-channels))
  423. (mbegin %store-monad
  424. (let ((config-file (cond ((string? config-file)
  425. ;; CONFIG-FILE has been passed typically via
  426. ;; 'guix system reconfigure CONFIG-FILE' so we
  427. ;; can assume it's valid: tell 'local-file' to
  428. ;; not emit a warning.
  429. (local-file (assume-valid-file-name config-file)
  430. "configuration.scm"))
  431. ((not config-file)
  432. #f)
  433. (else
  434. config-file))))
  435. (return `(("provenance" ,(provenance-file channels config-file))
  436. ,@(if channels
  437. `(("channels.scm"
  438. ,(plain-file "channels.scm"
  439. (object->pretty-string
  440. `(list
  441. ,@(map channel->code channels))))))
  442. '())
  443. ,@(if config-file
  444. `(("configuration.scm" ,config-file))
  445. '()))))))
  446. (define provenance-service-type
  447. (service-type (name 'provenance)
  448. (extensions
  449. (list (service-extension system-service-type
  450. provenance-entry)))
  451. (default-value #f) ;the OS config file
  452. (description
  453. "Store provenance information about the system in the system
  454. itself: the channels used when building the system, and its configuration
  455. file, when available.")))
  456. (define (sexp->system-provenance sexp)
  457. "Parse SEXP, an s-expression read from /run/current-system/provenance or
  458. similar, and return two values: the list of channels listed therein, and the
  459. OS configuration file or #f."
  460. (match sexp
  461. (('provenance ('version 0)
  462. ('channels channels ...)
  463. ('configuration-file config-file))
  464. (values (map sexp->channel channels)
  465. config-file))
  466. (_
  467. (values '() #f))))
  468. (define (system-provenance system)
  469. "Given SYSTEM, the file name of a system generation, return two values: the
  470. list of channels SYSTEM is built from, and its configuration file. If that
  471. information is missing, return the empty list (for channels) and possibly
  472. #false (for the configuration file)."
  473. (catch 'system-error
  474. (lambda ()
  475. (sexp->system-provenance
  476. (call-with-input-file (string-append system "/provenance")
  477. read)))
  478. (lambda _
  479. (values '() #f))))
  480. ;;;
  481. ;;; Cleanup.
  482. ;;;
  483. (define (cleanup-gexp _)
  484. "Return a gexp to clean up /tmp and similar places upon boot."
  485. (with-imported-modules '((guix build utils))
  486. #~(begin
  487. (use-modules (guix build utils))
  488. ;; Clean out /tmp and /var/run.
  489. ;;
  490. ;; XXX This needs to happen before service activations, so it
  491. ;; has to be here, but this also implicitly assumes that /tmp
  492. ;; and /var/run are on the root partition.
  493. (letrec-syntax ((fail-safe (syntax-rules ()
  494. ((_ exp rest ...)
  495. (begin
  496. (catch 'system-error
  497. (lambda () exp)
  498. (const #f))
  499. (fail-safe rest ...)))
  500. ((_)
  501. #t))))
  502. ;; Ignore I/O errors so the system can boot.
  503. (fail-safe
  504. ;; Remove stale Shadow lock files as they would lead to
  505. ;; failures of 'useradd' & co.
  506. (delete-file "/etc/group.lock")
  507. (delete-file "/etc/passwd.lock")
  508. (delete-file "/etc/.pwd.lock") ;from 'lckpwdf'
  509. ;; Force file names to be decoded as UTF-8. See
  510. ;; <https://bugs.gnu.org/26353>.
  511. (setenv "GUIX_LOCPATH"
  512. #+(file-append glibc-utf8-locales "/lib/locale"))
  513. (setlocale LC_CTYPE "en_US.utf8")
  514. (delete-file-recursively "/tmp")
  515. (delete-file-recursively "/var/run")
  516. (mkdir "/tmp")
  517. (chmod "/tmp" #o1777)
  518. (mkdir "/var/run")
  519. (chmod "/var/run" #o755)
  520. (delete-file-recursively "/run/udev/watch.old"))))))
  521. (define cleanup-service-type
  522. ;; Service that cleans things up in /tmp and similar.
  523. (service-type (name 'cleanup)
  524. (extensions
  525. (list (service-extension boot-service-type
  526. cleanup-gexp)))
  527. (description
  528. "Delete files from @file{/tmp}, @file{/var/run}, and other
  529. temporary locations at boot time.")))
  530. (define* (activation-service->script service)
  531. "Return as a monadic value the activation script for SERVICE, a service of
  532. ACTIVATION-SCRIPT-TYPE."
  533. (activation-script (service-value service)))
  534. (define (activation-script gexps)
  535. "Return the system's activation script, which evaluates GEXPS."
  536. (define actions
  537. (map (cut program-file "activate-service.scm" <>) gexps))
  538. (program-file "activate.scm"
  539. (with-imported-modules (source-module-closure
  540. '((gnu build activation)
  541. (guix build utils)))
  542. #~(begin
  543. (use-modules (gnu build activation)
  544. (guix build utils))
  545. ;; Make sure the user accounting database exists. If it
  546. ;; does not exist, 'setutxent' does not create it and
  547. ;; thus there is no accounting at all.
  548. (close-port (open-file "/var/run/utmpx" "a0"))
  549. ;; Same for 'wtmp', which is populated by mingetty et
  550. ;; al.
  551. (mkdir-p "/var/log")
  552. (close-port (open-file "/var/log/wtmp" "a0"))
  553. ;; Set up /run/current-system. Among other things this
  554. ;; sets up locales, which the activation snippets
  555. ;; executed below may expect.
  556. (activate-current-system)
  557. ;; Run the services' activation snippets.
  558. ;; TODO: Use 'load-compiled'.
  559. (for-each primitive-load '#$actions)))))
  560. (define (gexps->activation-gexp gexps)
  561. "Return a gexp that runs the activation script containing GEXPS."
  562. #~(primitive-load #$(activation-script gexps)))
  563. (define (activation-profile-entry gexps)
  564. "Return, as a monadic value, an entry for the activation script in the
  565. system directory."
  566. (mlet %store-monad ((activate (lower-object (activation-script gexps))))
  567. (return `(("activate" ,activate)))))
  568. (define (second-argument a b) b)
  569. (define activation-service-type
  570. (service-type (name 'activate)
  571. (extensions
  572. (list (service-extension boot-service-type
  573. gexps->activation-gexp)
  574. (service-extension system-service-type
  575. activation-profile-entry)))
  576. (compose identity)
  577. (extend second-argument)
  578. (description
  579. "Run @dfn{activation} code at boot time and upon
  580. @command{guix system reconfigure} completion.")))
  581. (define %activation-service
  582. ;; The activation service produces the activation script from the gexps it
  583. ;; receives.
  584. (service activation-service-type #t))
  585. (define %modprobe-wrapper
  586. ;; Wrapper for the 'modprobe' command that knows where modules live.
  587. ;;
  588. ;; This wrapper is typically invoked by the Linux kernel ('call_modprobe',
  589. ;; in kernel/kmod.c), a situation where the 'LINUX_MODULE_DIRECTORY'
  590. ;; environment variable is not set---hence the need for this wrapper.
  591. (let ((modprobe "/run/current-system/profile/bin/modprobe"))
  592. (program-file "modprobe"
  593. #~(begin
  594. (setenv "LINUX_MODULE_DIRECTORY"
  595. "/run/booted-system/kernel/lib/modules")
  596. ;; FIXME: Remove this crutch when the patch #40422,
  597. ;; updating to kmod 27 is merged.
  598. (setenv "MODPROBE_OPTIONS"
  599. "-C /etc/modprobe.d")
  600. (apply execl #$modprobe
  601. (cons #$modprobe (cdr (command-line))))))))
  602. (define %linux-kernel-activation
  603. ;; Activation of the Linux kernel running on the bare metal (as opposed to
  604. ;; running in a container.)
  605. #~(begin
  606. ;; Tell the kernel to use our 'modprobe' command.
  607. (activate-modprobe #$%modprobe-wrapper)
  608. ;; Let users debug their own processes!
  609. (activate-ptrace-attach)))
  610. (define %linux-bare-metal-service
  611. ;; The service that does things that are needed on the "bare metal", but not
  612. ;; necessary or impossible in a container.
  613. (simple-service 'linux-bare-metal
  614. activation-service-type
  615. %linux-kernel-activation))
  616. (define %hurd-rc-script
  617. ;; The RC script to be started upon boot.
  618. (program-file "rc"
  619. (with-imported-modules (source-module-closure
  620. '((guix build utils)
  621. (gnu build hurd-boot)
  622. (guix build syscalls)))
  623. #~(begin
  624. (use-modules (guix build utils)
  625. (gnu build hurd-boot)
  626. (guix build syscalls)
  627. (ice-9 match)
  628. (system repl repl)
  629. (srfi srfi-1)
  630. (srfi srfi-26))
  631. (boot-hurd-system)))))
  632. (define (hurd-rc-entry rc)
  633. "Return, as a monadic value, an entry for the RC script in the system
  634. directory."
  635. (mlet %store-monad ((rc (lower-object rc)))
  636. (return `(("rc" ,rc)))))
  637. (define hurd-startup-service-type
  638. ;; The service that creates the initial SYSTEM/rc startup file.
  639. (service-type (name 'startup)
  640. (extensions
  641. (list (service-extension system-service-type hurd-rc-entry)))
  642. (default-value %hurd-rc-script)))
  643. (define %hurd-startup-service
  644. ;; The service that produces the RC script.
  645. (service hurd-startup-service-type %hurd-rc-script))
  646. (define special-files-service-type
  647. ;; Service to install "special files" such as /bin/sh and /usr/bin/env.
  648. (service-type
  649. (name 'special-files)
  650. (extensions
  651. (list (service-extension activation-service-type
  652. (lambda (files)
  653. #~(activate-special-files '#$files)))))
  654. (compose concatenate)
  655. (extend append)
  656. (description
  657. "Add special files to the root file system---e.g.,
  658. @file{/usr/bin/env}.")))
  659. (define (extra-special-file file target)
  660. "Use TARGET as the \"special file\" FILE. For example, TARGET might be
  661. (file-append coreutils \"/bin/env\")
  662. and FILE could be \"/usr/bin/env\"."
  663. (simple-service (string->symbol (string-append "special-file-" file))
  664. special-files-service-type
  665. `((,file ,target))))
  666. (define (etc-directory service)
  667. "Return the directory for SERVICE, a service of type ETC-SERVICE-TYPE."
  668. (files->etc-directory (service-value service)))
  669. (define (files->etc-directory files)
  670. (define (assert-no-duplicates files)
  671. (let loop ((files files)
  672. (seen (set)))
  673. (match files
  674. (() #t)
  675. (((file _) rest ...)
  676. (when (set-contains? seen file)
  677. (raise (formatted-message (G_ "duplicate '~a' entry for /etc")
  678. file)))
  679. (loop rest (set-insert file seen))))))
  680. ;; Detect duplicates early instead of letting them through, eventually
  681. ;; leading to a build failure of "etc.drv".
  682. (assert-no-duplicates files)
  683. (file-union "etc" files))
  684. (define (etc-entry files)
  685. "Return an entry for the /etc directory consisting of FILES in the system
  686. directory."
  687. (with-monad %store-monad
  688. (return `(("etc" ,(files->etc-directory files))))))
  689. (define etc-service-type
  690. (service-type (name 'etc)
  691. (extensions
  692. (list
  693. (service-extension activation-service-type
  694. (lambda (files)
  695. (let ((etc
  696. (files->etc-directory files)))
  697. #~(activate-etc #$etc))))
  698. (service-extension system-service-type etc-entry)))
  699. (compose concatenate)
  700. (extend append)
  701. (description "Populate the @file{/etc} directory.")))
  702. (define (etc-service files)
  703. "Return a new service of ETC-SERVICE-TYPE that populates /etc with FILES.
  704. FILES must be a list of name/file-like object pairs."
  705. (service etc-service-type files))
  706. (define setuid-program-service-type
  707. (service-type (name 'setuid-program)
  708. (extensions
  709. (list (service-extension activation-service-type
  710. (lambda (programs)
  711. #~(activate-setuid-programs
  712. (list #$@programs))))))
  713. (compose concatenate)
  714. (extend append)
  715. (description
  716. "Populate @file{/run/setuid-programs} with the specified
  717. executables, making them setuid-root.")))
  718. (define (packages->profile-entry packages)
  719. "Return a system entry for the profile containing PACKAGES."
  720. ;; XXX: 'mlet' is needed here for one reason: to get the proper
  721. ;; '%current-target' and '%current-target-system' bindings when
  722. ;; 'packages->manifest' is called, and thus when the 'package-inputs'
  723. ;; etc. procedures are called on PACKAGES. That way, conditionals in those
  724. ;; inputs see the "correct" value of these two parameters. See
  725. ;; <https://issues.guix.gnu.org/44952>.
  726. (mlet %store-monad ((_ (current-target-system)))
  727. (return `(("profile" ,(profile
  728. (content (packages->manifest
  729. (delete-duplicates packages eq?)))))))))
  730. (define profile-service-type
  731. ;; The service that populates the system's profile---i.e.,
  732. ;; /run/current-system/profile. It is extended by package lists.
  733. (service-type (name 'profile)
  734. (extensions
  735. (list (service-extension system-service-type
  736. packages->profile-entry)))
  737. (compose concatenate)
  738. (extend append)
  739. (description
  740. "This is the @dfn{system profile}, available as
  741. @file{/run/current-system/profile}. It contains packages that the sysadmin
  742. wants to be globally available to all the system users.")))
  743. (define (firmware->activation-gexp firmware)
  744. "Return a gexp to make the packages listed in FIRMWARE loadable by the
  745. kernel."
  746. (let ((directory (directory-union "firmware" firmware)))
  747. ;; Tell the kernel where firmware is.
  748. #~(activate-firmware (string-append #$directory "/lib/firmware"))))
  749. (define firmware-service-type
  750. ;; The service that collects firmware.
  751. (service-type (name 'firmware)
  752. (extensions
  753. (list (service-extension activation-service-type
  754. firmware->activation-gexp)))
  755. (compose concatenate)
  756. (extend append)
  757. (description
  758. "Make ``firmware'' files loadable by the operating system
  759. kernel. Firmware may then be uploaded to some of the machine's devices, such
  760. as Wifi cards.")))
  761. (define (gc-roots->system-entry roots)
  762. "Return an entry in the system's output containing symlinks to ROOTS."
  763. (mlet %store-monad ((entry (gexp->derivation
  764. "gc-roots"
  765. #~(let ((roots '#$roots))
  766. (mkdir #$output)
  767. (chdir #$output)
  768. (for-each symlink
  769. roots
  770. (map number->string
  771. (iota (length roots))))))))
  772. (return (if (null? roots)
  773. '()
  774. `(("gc-roots" ,entry))))))
  775. (define gc-root-service-type
  776. ;; A service to associate extra garbage-collector roots to the system. This
  777. ;; is a simple hack that guarantees that the system retains references to
  778. ;; the given list of roots. Roots must be "lowerable" objects like
  779. ;; packages, or derivations.
  780. (service-type (name 'gc-roots)
  781. (extensions
  782. (list (service-extension system-service-type
  783. gc-roots->system-entry)))
  784. (compose concatenate)
  785. (extend append)
  786. (description
  787. "Register garbage-collector roots---i.e., store items that
  788. will not be reclaimed by the garbage collector.")
  789. (default-value '())))
  790. ;; Configuration for the Linux kernel builder.
  791. (define-record-type* <linux-builder-configuration>
  792. linux-builder-configuration
  793. make-linux-builder-configuration
  794. linux-builder-configuration?
  795. this-linux-builder-configuration
  796. (kernel linux-builder-configuration-kernel) ; package
  797. (modules linux-builder-configuration-modules (default '()))) ; list of packages
  798. (define (package-for-kernel target-kernel module-package)
  799. "Return a package like MODULE-PACKAGE, adapted for TARGET-KERNEL, if
  800. possible (that is if there's a LINUX keyword argument in the build system)."
  801. (package
  802. (inherit module-package)
  803. (arguments
  804. (substitute-keyword-arguments (package-arguments module-package)
  805. ((#:linux kernel #f)
  806. target-kernel)))))
  807. (define (linux-builder-configuration->system-entry config)
  808. "Return the kernel entry of the 'system' directory."
  809. (let* ((kernel (linux-builder-configuration-kernel config))
  810. (modules (linux-builder-configuration-modules config))
  811. (kernel (profile
  812. (content (packages->manifest
  813. (cons kernel
  814. (map (lambda (module)
  815. (cond
  816. ((package? module)
  817. (package-for-kernel kernel module))
  818. ;; support (,package "kernel-module-output")
  819. ((and (list? module) (package? (car module)))
  820. (cons (package-for-kernel kernel
  821. (car module))
  822. (cdr module)))
  823. (else
  824. module)))
  825. modules))))
  826. (hooks (list linux-module-database)))))
  827. (with-monad %store-monad
  828. (return `(("kernel" ,kernel))))))
  829. (define linux-builder-service-type
  830. (service-type (name 'linux-builder)
  831. (extensions
  832. (list (service-extension system-service-type
  833. linux-builder-configuration->system-entry)))
  834. (default-value '())
  835. (compose identity)
  836. (extend (lambda (config modifiers)
  837. (if (null? modifiers)
  838. config
  839. ((apply compose modifiers) config))))
  840. (description "Builds the linux-libre kernel profile, containing
  841. the kernel itself and any linux-loadable kernel modules. This can be extended
  842. with a function that accepts the current configuration and returns a new
  843. configuration.")))
  844. (define (linux-loadable-module-builder-modifier modules)
  845. "Extends linux-builder-service-type by appending the given MODULES to the
  846. configuration of linux-builder-service-type."
  847. (lambda (config)
  848. (linux-builder-configuration
  849. (inherit config)
  850. (modules (append (linux-builder-configuration-modules config)
  851. modules)))))
  852. (define linux-loadable-module-service-type
  853. (service-type (name 'linux-loadable-modules)
  854. (extensions
  855. (list (service-extension linux-builder-service-type
  856. linux-loadable-module-builder-modifier)))
  857. (default-value '())
  858. (compose concatenate)
  859. (extend append)
  860. (description "Adds packages and package outputs as modules
  861. included in the booted linux-libre profile. Other services can extend this
  862. service type to add particular modules to the set of linux-loadable modules.")))
  863. ;;;
  864. ;;; Service folding.
  865. ;;;
  866. (define-condition-type &missing-target-service-error &service-error
  867. missing-target-service-error?
  868. (service missing-target-service-error-service)
  869. (target-type missing-target-service-error-target-type))
  870. (define-condition-type &ambiguous-target-service-error &service-error
  871. ambiguous-target-service-error?
  872. (service ambiguous-target-service-error-service)
  873. (target-type ambiguous-target-service-error-target-type))
  874. (define (missing-target-error service target-type)
  875. (raise
  876. (condition (&missing-target-service-error
  877. (service service)
  878. (target-type target-type))
  879. (&message
  880. (message
  881. (format #f (G_ "no target of type '~a' for service '~a'")
  882. (service-type-name target-type)
  883. (service-type-name
  884. (service-kind service))))))))
  885. (define (service-back-edges services)
  886. "Return a procedure that, when passed a <service>, returns the list of
  887. <service> objects that depend on it."
  888. (define (add-edges service edges)
  889. (define (add-edge extension edges)
  890. (let ((target-type (service-extension-target extension)))
  891. (match (filter (lambda (service)
  892. (eq? (service-kind service) target-type))
  893. services)
  894. ((target)
  895. (vhash-consq target service edges))
  896. (()
  897. (missing-target-error service target-type))
  898. (x
  899. (raise
  900. (condition (&ambiguous-target-service-error
  901. (service service)
  902. (target-type target-type))
  903. (&message
  904. (message
  905. (format #f
  906. (G_ "more than one target service of type '~a'")
  907. (service-type-name target-type))))))))))
  908. (fold add-edge edges (service-type-extensions (service-kind service))))
  909. (let ((edges (fold add-edges vlist-null services)))
  910. (lambda (node)
  911. (reverse (vhash-foldq* cons '() node edges)))))
  912. (define (instantiate-missing-services services)
  913. "Return SERVICES, a list, augmented with any services targeted by extensions
  914. and missing from SERVICES. Only service types with a default value can be
  915. instantiated; other missing services lead to a
  916. '&missing-target-service-error'."
  917. (define (adjust-service-list svc result instances)
  918. (fold2 (lambda (extension result instances)
  919. (define target-type
  920. (service-extension-target extension))
  921. (match (vhash-assq target-type instances)
  922. (#f
  923. (let ((default (service-type-default-value target-type)))
  924. (if (eq? &no-default-value default)
  925. (missing-target-error svc target-type)
  926. (let ((new (service target-type)))
  927. (values (cons new result)
  928. (vhash-consq target-type new instances))))))
  929. (_
  930. (values result instances))))
  931. result
  932. instances
  933. (service-type-extensions (service-kind svc))))
  934. (let loop ((services services))
  935. (define instances
  936. (fold (lambda (service result)
  937. (vhash-consq (service-kind service) service
  938. result))
  939. vlist-null services))
  940. (define adjusted
  941. (fold2 adjust-service-list
  942. services instances
  943. services))
  944. ;; If we instantiated services, they might in turn depend on missing
  945. ;; services. Loop until we've reached fixed point.
  946. (if (= (length adjusted) (vlist-length instances))
  947. adjusted
  948. (loop adjusted))))
  949. (define* (fold-services services
  950. #:key (target-type system-service-type))
  951. "Fold SERVICES by propagating their extensions down to the root of type
  952. TARGET-TYPE; return the root service adjusted accordingly."
  953. (define dependents
  954. (service-back-edges services))
  955. (define (matching-extension target)
  956. (let ((target (service-kind target)))
  957. (match-lambda
  958. (($ <service-extension> type)
  959. (eq? type target)))))
  960. (define (apply-extension target)
  961. (lambda (service)
  962. (match (find (matching-extension target)
  963. (service-type-extensions (service-kind service)))
  964. (($ <service-extension> _ compute)
  965. (compute (service-value service))))))
  966. (match (filter (lambda (service)
  967. (eq? (service-kind service) target-type))
  968. services)
  969. ((sink)
  970. ;; Use the state monad to keep track of already-visited services in the
  971. ;; graph and to memoize their value once folded.
  972. (run-with-state
  973. (let loop ((sink sink))
  974. (mlet %state-monad ((visited (current-state)))
  975. (match (vhash-assq sink visited)
  976. (#f
  977. (mlet* %state-monad
  978. ((dependents (mapm %state-monad loop (dependents sink)))
  979. (visited (current-state))
  980. (extensions -> (map (apply-extension sink) dependents))
  981. (extend -> (service-type-extend (service-kind sink)))
  982. (compose -> (service-type-compose (service-kind sink)))
  983. (params -> (service-value sink))
  984. (service
  985. ->
  986. ;; Distinguish COMPOSE and EXTEND because PARAMS typically
  987. ;; has a different type than the elements of EXTENSIONS.
  988. (if extend
  989. (service (service-kind sink)
  990. (extend params (compose extensions)))
  991. sink)))
  992. (mbegin %state-monad
  993. (set-current-state (vhash-consq sink service visited))
  994. (return service))))
  995. ((_ . service) ;SINK was already visited
  996. (return service)))))
  997. vlist-null))
  998. (()
  999. (raise
  1000. (make-compound-condition
  1001. (condition (&missing-target-service-error
  1002. (service #f)
  1003. (target-type target-type)))
  1004. (formatted-message (G_ "service of type '~a' not found")
  1005. (service-type-name target-type)))))
  1006. (x
  1007. (raise
  1008. (condition (&ambiguous-target-service-error
  1009. (service #f)
  1010. (target-type target-type))
  1011. (&message
  1012. (message
  1013. (format #f
  1014. (G_ "more than one target service of type '~a'")
  1015. (service-type-name target-type)))))))))
  1016. ;;; services.scm ends here.