shepherd.scm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2013-2016, 2018-2022 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
  4. ;;; Copyright © 2018 Carlo Zancanaro <carlo@zancanaro.id.au>
  5. ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  6. ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
  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 shepherd)
  23. #:use-module (guix ui)
  24. #:use-module (guix sets)
  25. #:use-module (guix gexp)
  26. #:use-module (guix store)
  27. #:use-module (guix records)
  28. #:use-module (guix packages)
  29. #:use-module (guix derivations) ;imported-modules, etc.
  30. #:use-module (guix utils)
  31. #:use-module (gnu services)
  32. #:use-module (gnu services herd)
  33. #:use-module (gnu packages admin)
  34. #:use-module (ice-9 match)
  35. #:use-module (ice-9 vlist)
  36. #:use-module (srfi srfi-1)
  37. #:use-module (srfi srfi-26)
  38. #:use-module (srfi srfi-34)
  39. #:use-module (srfi srfi-35)
  40. #:export (shepherd-configuration
  41. shepherd-configuration?
  42. shepherd-configuration-shepherd
  43. shepherd-configuration-services
  44. shepherd-root-service-type
  45. %shepherd-root-service
  46. shepherd-service-type
  47. shepherd-service
  48. shepherd-service?
  49. shepherd-service-documentation
  50. shepherd-service-provision
  51. shepherd-service-canonical-name
  52. shepherd-service-requirement
  53. shepherd-service-one-shot?
  54. shepherd-service-respawn?
  55. shepherd-service-start
  56. shepherd-service-stop
  57. shepherd-service-auto-start?
  58. shepherd-service-modules
  59. shepherd-action
  60. shepherd-action?
  61. shepherd-action-name
  62. shepherd-action-documentation
  63. shepherd-action-procedure
  64. %default-modules
  65. shepherd-service-file
  66. shepherd-service-lookup-procedure
  67. shepherd-service-back-edges
  68. shepherd-service-upgrade
  69. user-processes-service-type
  70. assert-valid-graph))
  71. ;;; Commentary:
  72. ;;;
  73. ;;; Instantiating system services as a shepherd configuration file.
  74. ;;;
  75. ;;; Code:
  76. (define-record-type* <shepherd-configuration>
  77. shepherd-configuration make-shepherd-configuration
  78. shepherd-configuration?
  79. (shepherd shepherd-configuration-shepherd
  80. (default shepherd-0.9)) ; file-like
  81. (services shepherd-configuration-services
  82. (default '()))) ; list of <shepherd-service>
  83. (define (shepherd-boot-gexp config)
  84. "Return a gexp starting the shepherd service."
  85. (let ((shepherd (shepherd-configuration-shepherd config))
  86. (services (shepherd-configuration-services config)))
  87. #~(begin
  88. ;; Keep track of the booted system.
  89. (false-if-exception (delete-file "/run/booted-system"))
  90. ;; Make /run/booted-system, an indirect GC root, point to the store item
  91. ;; /run/current-system points to. Use 'canonicalize-path' rather than
  92. ;; 'readlink' to make sure we get the store item.
  93. (symlink (canonicalize-path "/run/current-system")
  94. "/run/booted-system")
  95. ;; Close any remaining open file descriptors to be on the safe
  96. ;; side. This must be the very last thing we do, because
  97. ;; Guile has internal FDs such as 'sleep_pipe' that need to be
  98. ;; alive.
  99. (let loop ((fd 3))
  100. (when (< fd 1024)
  101. (false-if-exception (close-fdes fd))
  102. (loop (+ 1 fd))))
  103. ;; Start shepherd.
  104. (execl #$(file-append shepherd "/bin/shepherd")
  105. "shepherd" "--config"
  106. #$(shepherd-configuration-file services shepherd)))))
  107. (define shepherd-packages
  108. (compose list shepherd-configuration-shepherd))
  109. (define shepherd-root-service-type
  110. (service-type
  111. (name 'shepherd-root)
  112. ;; Extending the root shepherd service (aka. PID 1) happens by
  113. ;; concatenating the list of services provided by the extensions.
  114. (compose concatenate)
  115. (extend (lambda (config extra-services)
  116. (shepherd-configuration
  117. (inherit config)
  118. (services (append (shepherd-configuration-services config)
  119. extra-services)))))
  120. (extensions (list (service-extension boot-service-type
  121. shepherd-boot-gexp)
  122. (service-extension profile-service-type
  123. shepherd-packages)))
  124. (default-value (shepherd-configuration))
  125. (description
  126. "Run the GNU Shepherd as PID 1---i.e., the operating system's first
  127. process. The Shepherd takes care of managing services such as daemons by
  128. ensuring they are started and stopped in the right order.")))
  129. (define %shepherd-root-service
  130. ;; The root shepherd service, aka. PID 1. Its parameter is a
  131. ;; <shepherd-configuration>.
  132. (service shepherd-root-service-type))
  133. (define-syntax shepherd-service-type
  134. (syntax-rules (description)
  135. "Return a <service-type> denoting a simple shepherd service--i.e., the type
  136. for a service that extends SHEPHERD-ROOT-SERVICE-TYPE and nothing else. When
  137. DEFAULT is given, use it as the service's default value."
  138. ((_ service-name proc default (description text))
  139. (service-type
  140. (name service-name)
  141. (extensions
  142. (list (service-extension shepherd-root-service-type
  143. (compose list proc))))
  144. (default-value default)
  145. (description text)))
  146. ((_ service-name proc (description text))
  147. (service-type
  148. (name service-name)
  149. (extensions
  150. (list (service-extension shepherd-root-service-type
  151. (compose list proc))))
  152. (description text)))))
  153. (define %default-imported-modules
  154. ;; Default set of modules imported for a service's consumption.
  155. '((guix build utils)
  156. (guix build syscalls)))
  157. (define %default-modules
  158. ;; Default set of modules visible in a service's file.
  159. `((shepherd service)
  160. (oop goops)
  161. ((guix build utils) #:hide (delete))
  162. (guix build syscalls)))
  163. (define-record-type* <shepherd-service>
  164. shepherd-service make-shepherd-service
  165. shepherd-service?
  166. (documentation shepherd-service-documentation ;string
  167. (default "[No documentation.]"))
  168. (provision shepherd-service-provision) ;list of symbols
  169. (requirement shepherd-service-requirement ;list of symbols
  170. (default '()))
  171. (one-shot? shepherd-service-one-shot? ;Boolean
  172. (default #f))
  173. (respawn? shepherd-service-respawn? ;Boolean
  174. (default #t))
  175. (start shepherd-service-start) ;g-expression (procedure)
  176. (stop shepherd-service-stop ;g-expression (procedure)
  177. (default #~(const #f)))
  178. (actions shepherd-service-actions ;list of <shepherd-action>
  179. (default '()))
  180. (auto-start? shepherd-service-auto-start? ;Boolean
  181. (default #t))
  182. (modules shepherd-service-modules ;list of module names
  183. (default %default-modules)))
  184. (define-record-type* <shepherd-action>
  185. shepherd-action make-shepherd-action
  186. shepherd-action?
  187. (name shepherd-action-name) ;symbol
  188. (procedure shepherd-action-procedure) ;gexp
  189. (documentation shepherd-action-documentation)) ;string
  190. (define (shepherd-service-canonical-name service)
  191. "Return the 'canonical name' of SERVICE."
  192. (first (shepherd-service-provision service)))
  193. (define (assert-valid-graph services)
  194. "Raise an error if SERVICES does not define a valid shepherd service graph,
  195. for instance if a service requires a nonexistent service, or if more than one
  196. service uses a given name.
  197. These are constraints that shepherd's 'register-service' verifies but we'd
  198. better verify them here statically than wait until PID 1 halts with an
  199. assertion failure."
  200. (define provisions
  201. ;; The set of provisions (symbols). Bail out if a symbol is given more
  202. ;; than once.
  203. (fold (lambda (service set)
  204. (define (assert-unique symbol)
  205. (when (set-contains? set symbol)
  206. (raise (condition
  207. (&message
  208. (message
  209. (format #f (G_ "service '~a' provided more than once")
  210. symbol)))))))
  211. (for-each assert-unique (shepherd-service-provision service))
  212. (fold set-insert set (shepherd-service-provision service)))
  213. (setq 'shepherd)
  214. services))
  215. (define (assert-satisfied-requirements service)
  216. ;; Bail out if the requirements of SERVICE aren't satisfied.
  217. (for-each (lambda (requirement)
  218. (unless (set-contains? provisions requirement)
  219. (raise (condition
  220. (&message
  221. (message
  222. (format #f (G_ "service '~a' requires '~a', \
  223. which is not provided by any service")
  224. (match (shepherd-service-provision service)
  225. ((head . _) head)
  226. (_ service))
  227. requirement)))))))
  228. (shepherd-service-requirement service)))
  229. (for-each assert-satisfied-requirements services))
  230. (define %store-characters
  231. ;; Valid store characters; see 'checkStoreName' in the daemon.
  232. (string->char-set
  233. "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-._?="))
  234. (define (shepherd-service-file-name service)
  235. "Return the file name where the initialization code for SERVICE is to be
  236. stored."
  237. (let ((provisions (string-join (map symbol->string
  238. (shepherd-service-provision service)))))
  239. (string-append "shepherd-"
  240. (string-map (lambda (chr)
  241. (if (char-set-contains? %store-characters chr)
  242. chr
  243. #\-))
  244. provisions)
  245. ".scm")))
  246. (define (shepherd-service-file service)
  247. "Return a file defining SERVICE."
  248. (scheme-file (shepherd-service-file-name service)
  249. (with-imported-modules %default-imported-modules
  250. #~(begin
  251. (use-modules #$@(shepherd-service-modules service))
  252. (make <service>
  253. #:docstring '#$(shepherd-service-documentation service)
  254. #:provides '#$(shepherd-service-provision service)
  255. #:requires '#$(shepherd-service-requirement service)
  256. ;; The 'one-shot?' slot is new in Shepherd 0.6.0.
  257. ;; Older versions ignore it.
  258. #:one-shot? '#$(shepherd-service-one-shot? service)
  259. #:respawn? '#$(shepherd-service-respawn? service)
  260. #:start #$(shepherd-service-start service)
  261. #:stop #$(shepherd-service-stop service)
  262. #:actions
  263. (make-actions
  264. #$@(map (match-lambda
  265. (($ <shepherd-action> name proc doc)
  266. #~(#$name #$doc #$proc)))
  267. (shepherd-service-actions service))))))))
  268. (define (scm->go file shepherd)
  269. "Compile FILE, which contains code to be loaded by shepherd's config file,
  270. and return the resulting '.go' file. SHEPHERD is used as shepherd package."
  271. (define shepherd&co
  272. (cons shepherd
  273. (match (lookup-package-input shepherd "guile-fibers")
  274. (#f '())
  275. (fibers (list fibers)))))
  276. (let-system (system target)
  277. (with-extensions shepherd&co
  278. (computed-file (string-append (basename (scheme-file-name file) ".scm")
  279. ".go")
  280. #~(begin
  281. (use-modules (system base compile)
  282. (system base target))
  283. ;; Do the same as the Shepherd's 'load-in-user-module'.
  284. (let ((env (make-fresh-user-module)))
  285. (module-use! env (resolve-interface '(oop goops)))
  286. (module-use! env (resolve-interface '(shepherd service)))
  287. (with-target #$(or target #~%host-type)
  288. (lambda _
  289. (compile-file #$file #:output-file #$output
  290. #:env env)))))
  291. ;; It's faster to build locally than to download.
  292. #:options '(#:local-build? #t
  293. #:substitutable? #f)))))
  294. (define (shepherd-configuration-file services shepherd)
  295. "Return the shepherd configuration file for SERVICES. SHEPHERD is used
  296. as shepherd package."
  297. (assert-valid-graph services)
  298. (let ((files (map shepherd-service-file services))
  299. (scm->go (cute scm->go <> shepherd)))
  300. (define config
  301. #~(begin
  302. (use-modules (srfi srfi-34)
  303. (system repl error-handling))
  304. ;; Specify the default environment visible to all the services.
  305. ;; Without this statement, all the environment variables of PID 1
  306. ;; are inherited by child services.
  307. (default-environment-variables
  308. '("PATH=/run/current-system/profile/bin"))
  309. ;; Booting off a DVD, especially on a slow machine, can make
  310. ;; everything slow. Thus, increase the timeout compared to the
  311. ;; default 5s in the Shepherd 0.7.0. See
  312. ;; <https://bugs.gnu.org/40572>.
  313. (default-pid-file-timeout 30)
  314. ;; Arrange to spawn a REPL if something goes wrong. This is better
  315. ;; than a kernel panic.
  316. (call-with-error-handling
  317. (lambda ()
  318. (apply register-services
  319. (parameterize ((current-warning-port
  320. (%make-void-port "w")))
  321. (map load-compiled '#$(map scm->go files))))))
  322. (format #t "starting services...~%")
  323. (let ((services-to-start
  324. '#$(append-map shepherd-service-provision
  325. (filter shepherd-service-auto-start?
  326. services))))
  327. (if (defined? 'start-in-the-background)
  328. (start-in-the-background services-to-start)
  329. (for-each (lambda (service) ;pre-0.9.0 compatibility
  330. (guard (c ((service-error? c)
  331. (format (current-error-port)
  332. "failed to start service '~a'~%"
  333. service)))
  334. (start service)))
  335. services-to-start))
  336. ;; Hang up stdin. At this point, we assume that 'start' methods
  337. ;; that required user interaction on the console (e.g.,
  338. ;; 'cryptsetup open' invocations, post-fsck emergency REPL) have
  339. ;; completed. User interaction becomes impossible after this
  340. ;; call; this avoids situations where services wrongfully lead
  341. ;; PID 1 to read from stdin (the console), which users may not
  342. ;; have access to (see <https://bugs.gnu.org/23697>).
  343. (redirect-port (open-input-file "/dev/null")
  344. (current-input-port)))))
  345. (scheme-file "shepherd.conf" config)))
  346. (define* (shepherd-service-lookup-procedure services
  347. #:optional
  348. (provision
  349. shepherd-service-provision))
  350. "Return a procedure that, when passed a symbol, return the item among
  351. SERVICES that provides this symbol. PROVISION must be a one-argument
  352. procedure that takes a service and returns the list of symbols it provides."
  353. (let ((services (fold (lambda (service result)
  354. (fold (cut vhash-consq <> service <>)
  355. result
  356. (provision service)))
  357. vlist-null
  358. services)))
  359. (lambda (name)
  360. (match (vhash-assq name services)
  361. ((_ . service) service)
  362. (#f #f)))))
  363. (define* (shepherd-service-back-edges services
  364. #:key
  365. (provision shepherd-service-provision)
  366. (requirement shepherd-service-requirement))
  367. "Return a procedure that, when given a <shepherd-service> from SERVICES,
  368. returns the list of <shepherd-service> that depend on it.
  369. Use PROVISION and REQUIREMENT as one-argument procedures that return the
  370. symbols provided/required by a service."
  371. (define provision->service
  372. (shepherd-service-lookup-procedure services provision))
  373. (define edges
  374. (fold (lambda (service edges)
  375. (fold (lambda (requirement edges)
  376. (vhash-consq (provision->service requirement) service
  377. edges))
  378. edges
  379. (requirement service)))
  380. vlist-null
  381. services))
  382. (lambda (service)
  383. (vhash-foldq* cons '() service edges)))
  384. (define (shepherd-service-upgrade live target)
  385. "Return two values: the subset of LIVE (a list of <live-service>) that needs
  386. to be unloaded, and the subset of TARGET (a list of <shepherd-service>) that
  387. need to be restarted to complete their upgrade."
  388. (define (essential? service)
  389. (memq (first (live-service-provision service))
  390. '(root shepherd)))
  391. (define lookup-target
  392. (shepherd-service-lookup-procedure target
  393. shepherd-service-provision))
  394. (define lookup-live
  395. (shepherd-service-lookup-procedure live
  396. live-service-provision))
  397. (define (running? service)
  398. (and=> (lookup-live (shepherd-service-canonical-name service))
  399. live-service-running))
  400. (define live-service-dependents
  401. (shepherd-service-back-edges live
  402. #:provision live-service-provision
  403. #:requirement live-service-requirement))
  404. (define (obsolete? service)
  405. (match (lookup-target (first (live-service-provision service)))
  406. (#f (every obsolete? (live-service-dependents service)))
  407. (_ #f)))
  408. (define to-restart
  409. ;; Restart services that are currently running.
  410. (filter running? target))
  411. (define to-unload
  412. ;; Unload services that are no longer required. Essential services must
  413. ;; be kept and transient services such as inetd child services should be
  414. ;; kept as well--they'll vanish eventually.
  415. (remove (lambda (live)
  416. (or (essential? live)
  417. (live-service-transient? live)))
  418. (filter obsolete? live)))
  419. (values to-unload to-restart))
  420. ;;;
  421. ;;; User processes.
  422. ;;;
  423. (define %do-not-kill-file
  424. ;; Name of the file listing PIDs of processes that must survive when halting
  425. ;; the system. Typical example is user-space file systems.
  426. "/etc/shepherd/do-not-kill")
  427. (define (user-processes-shepherd-service requirements)
  428. "Return the 'user-processes' Shepherd service with dependencies on
  429. REQUIREMENTS (a list of service names).
  430. This is a synchronization point used to make sure user processes and daemons
  431. get started only after crucial initial services have been started---file
  432. system mounts, etc. This is similar to the 'sysvinit' target in systemd."
  433. (define grace-delay
  434. ;; Delay after sending SIGTERM and before sending SIGKILL.
  435. 4)
  436. (list (shepherd-service
  437. (documentation "When stopped, terminate all user processes.")
  438. (provision '(user-processes))
  439. (requirement requirements)
  440. (start #~(const #t))
  441. (stop #~(lambda _
  442. (define (kill-except omit signal)
  443. ;; Kill all the processes with SIGNAL except those listed
  444. ;; in OMIT and the current process.
  445. (let ((omit (cons (getpid) omit)))
  446. (for-each (lambda (pid)
  447. (unless (memv pid omit)
  448. (false-if-exception
  449. (kill pid signal))))
  450. (processes))))
  451. (define omitted-pids
  452. ;; List of PIDs that must not be killed.
  453. (if (file-exists? #$%do-not-kill-file)
  454. (map string->number
  455. (call-with-input-file #$%do-not-kill-file
  456. (compose string-tokenize
  457. (@ (ice-9 rdelim) read-string))))
  458. '()))
  459. (define (now)
  460. (car (gettimeofday)))
  461. (define (sleep* n)
  462. ;; Really sleep N seconds.
  463. ;; Work around <http://bugs.gnu.org/19581>.
  464. (define start (now))
  465. (let loop ((elapsed 0))
  466. (when (> n elapsed)
  467. (sleep (- n elapsed))
  468. (loop (- (now) start)))))
  469. (define lset= (@ (srfi srfi-1) lset=))
  470. (display "sending all processes the TERM signal\n")
  471. (if (null? omitted-pids)
  472. (begin
  473. ;; Easy: terminate all of them.
  474. (kill -1 SIGTERM)
  475. (sleep* #$grace-delay)
  476. (kill -1 SIGKILL))
  477. (begin
  478. ;; Kill them all except OMITTED-PIDS. XXX: We would
  479. ;; like to (kill -1 SIGSTOP) to get a fixed list of
  480. ;; processes, like 'killall5' does, but that seems
  481. ;; unreliable.
  482. (kill-except omitted-pids SIGTERM)
  483. (sleep* #$grace-delay)
  484. (kill-except omitted-pids SIGKILL)
  485. (delete-file #$%do-not-kill-file)))
  486. (let wait ()
  487. ;; Reap children, if any, so that we don't end up with
  488. ;; zombies and enter an infinite loop.
  489. (let reap-children ()
  490. (define result
  491. (false-if-exception
  492. (waitpid WAIT_ANY (if (null? omitted-pids)
  493. 0
  494. WNOHANG))))
  495. (when (and (pair? result)
  496. (not (zero? (car result))))
  497. (reap-children)))
  498. (let ((pids (processes)))
  499. (unless (lset= = pids (cons 1 omitted-pids))
  500. (format #t "waiting for process termination\
  501. (processes left: ~s)~%"
  502. pids)
  503. (sleep* 2)
  504. (wait))))
  505. (display "all processes have been terminated\n")
  506. #f))
  507. (respawn? #f))))
  508. (define user-processes-service-type
  509. (service-type
  510. (name 'user-processes)
  511. (extensions (list (service-extension shepherd-root-service-type
  512. user-processes-shepherd-service)))
  513. (compose concatenate)
  514. (extend append)
  515. ;; The value is the list of Shepherd services 'user-processes' depends on.
  516. ;; Extensions can add new services to this list.
  517. (default-value '())
  518. (description "The @code{user-processes} service is responsible for
  519. terminating all the processes so that the root file system can be re-mounted
  520. read-only, just before rebooting/halting. Processes still running after a few
  521. seconds after @code{SIGTERM} has been sent are terminated with
  522. @code{SIGKILL}.")))
  523. ;;; shepherd.scm ends here