services.scm 50 KB

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