gnu: babl: Update to 0.1.28.
[jackhill/guix/guix.git] / gnu / services / herd.scm
CommitLineData
240b57f0
LC
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org>
5e03b122 3;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
240b57f0
LC
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20(define-module (gnu services herd)
240b57f0 21 #:use-module (srfi srfi-1)
183605c8 22 #:use-module (srfi srfi-9)
240b57f0 23 #:use-module (srfi srfi-11)
8bf92e39
LC
24 #:use-module (srfi srfi-34)
25 #:use-module (srfi srfi-35)
240b57f0 26 #:use-module (ice-9 match)
5e03b122
MO
27 #:export (%shepherd-socket-file
28
29 shepherd-error?
8bf92e39
LC
30 service-not-found-error?
31 service-not-found-error-service
32 action-not-found-error?
33 action-not-found-error-service
34 action-not-found-error-action
35 action-exception-error?
36 action-exception-error-service
37 action-exception-error-action
38 action-exception-error-key
39 action-exception-error-arguments
40 unknown-shepherd-error?
41 unknown-shepherd-error-sexp
42
183605c8
LC
43 live-service?
44 live-service-provision
45 live-service-requirement
46 live-service-running
47
8bf92e39 48 current-services
240b57f0
LC
49 unload-services
50 unload-service
51 load-services
52 start-service))
53
54;;; Commentary:
55;;;
56;;; This module provides an interface to the GNU Shepherd, similar to the
57;;; 'herd' command. Essentially it implements a subset of the (shepherd comm)
58;;; module, but focusing only on the parts relevant to 'guix system
59;;; reconfigure'.
60;;;
61;;; Code:
62
63(define %shepherd-socket-file
5e03b122 64 (make-parameter "/var/run/shepherd/socket"))
240b57f0 65
5e03b122 66(define* (open-connection #:optional (file (%shepherd-socket-file)))
240b57f0
LC
67 "Open a connection to the daemon, using the Unix-domain socket at FILE, and
68return the socket."
69 ;; The protocol is sexp-based and UTF-8-encoded.
70 (with-fluids ((%default-port-encoding "UTF-8"))
71 (let ((sock (socket PF_UNIX SOCK_STREAM 0))
72 (address (make-socket-address PF_UNIX file)))
73 (catch 'system-error
74 (lambda ()
75 (connect sock address)
76 (setvbuf sock _IOFBF 1024)
77 sock)
1d6b7d58
LC
78 (lambda args
79 (close-port sock)
80 (apply throw args))))))
240b57f0
LC
81
82(define-syntax-rule (with-shepherd connection body ...)
83 "Evaluate BODY... with CONNECTION bound to an open socket to PID 1."
84 (let ((connection (open-connection)))
1d6b7d58 85 body ...))
240b57f0 86
8bf92e39
LC
87(define-condition-type &shepherd-error &error
88 shepherd-error?)
89
90(define-condition-type &service-not-found-error &shepherd-error
91 service-not-found-error?
92 (service service-not-found-error-service))
93
94(define-condition-type &action-not-found-error &shepherd-error
95 action-not-found-error?
96 (service action-not-found-error-service)
97 (action action-not-found-error-action))
98
99(define-condition-type &action-exception-error &shepherd-error
100 action-exception-error?
101 (service action-exception-error-service)
102 (action action-exception-error-action)
103 (key action-exception-error-key)
104 (args action-exception-error-arguments))
105
106(define-condition-type &unknown-shepherd-error &shepherd-error
107 unknown-shepherd-error?
108 (sexp unknown-shepherd-error-sexp))
109
110(define (raise-shepherd-error error)
111 "Raise an error condition corresponding to ERROR, an sexp received by a
112shepherd client in reply to COMMAND, a command object. Return #t if ERROR
113does not denote an error."
240b57f0
LC
114 (match error
115 (('error ('version 0 x ...) 'service-not-found service)
8bf92e39
LC
116 (raise (condition (&service-not-found-error
117 (service service)))))
240b57f0 118 (('error ('version 0 x ...) 'action-not-found action service)
8bf92e39
LC
119 (raise (condition (&action-not-found-error
120 (service service)
121 (action action)))))
240b57f0
LC
122 (('error ('version 0 x ...) 'action-exception action service
123 key (args ...))
8bf92e39
LC
124 (raise (condition (&action-exception-error
125 (service service)
126 (action action)
127 (key key) (args args)))))
240b57f0 128 (('error . _)
8bf92e39 129 (raise (condition (&unknown-shepherd-error (sexp error)))))
240b57f0
LC
130 (#f ;not an error
131 #t)))
132
133(define (display-message message)
8bf92e39 134 (format (current-error-port) "shepherd: ~a~%" message))
240b57f0
LC
135
136(define* (invoke-action service action arguments cont)
137 "Invoke ACTION on SERVICE with ARGUMENTS. On success, call CONT with the
138result. Otherwise return #f."
139 (with-shepherd sock
140 (write `(shepherd-command (version 0)
141 (action ,action)
142 (service ,service)
143 (arguments ,arguments)
144 (directory ,(getcwd)))
145 sock)
146 (force-output sock)
147
148 (match (read sock)
149 (('reply ('version 0 _ ...) ('result (result)) ('error #f)
150 ('messages messages))
151 (for-each display-message messages)
152 (cont result))
153 (('reply ('version 0 x ...) ('result y) ('error error)
154 ('messages messages))
155 (for-each display-message messages)
8bf92e39 156 (raise-shepherd-error error)
240b57f0
LC
157 #f)
158 (x
8bf92e39 159 ;; invalid reply
240b57f0
LC
160 #f))))
161
162(define-syntax-rule (with-shepherd-action service (action args ...)
163 result body ...)
164 (invoke-action service action (list args ...)
165 (lambda (result) body ...)))
166
167(define-syntax alist-let*
168 (syntax-rules ()
169 "Bind the given KEYs in EXP to the corresponding items in ALIST. ALIST
170is assumed to be a list of two-element tuples rather than a traditional list
171of pairs."
172 ((_ alist (key ...) exp ...)
173 (let ((key (and=> (assoc-ref alist 'key) car)) ...)
174 exp ...))))
175
183605c8
LC
176;; Information about live Shepherd services.
177(define-record-type <live-service>
178 (live-service provision requirement running)
179 live-service?
180 (provision live-service-provision) ;list of symbols
181 (requirement live-service-requirement) ;list of symbols
182 (running live-service-running)) ;#f | object
183
240b57f0 184(define (current-services)
183605c8
LC
185 "Return the list of currently defined Shepherd services, represented as
186<live-service> objects. Return #f if the list of services could not be
187obtained."
240b57f0
LC
188 (with-shepherd-action 'root ('status) services
189 (match services
190 ((('service ('version 0 _ ...) _ ...) ...)
183605c8
LC
191 (map (lambda (service)
192 (alist-let* service (provides requires running)
193 (live-service provides requires running)))
194 services))
240b57f0 195 (x
183605c8 196 #f))))
240b57f0
LC
197
198(define (unload-service service)
199 "Unload SERVICE, a symbol name; return #t on success."
200 (with-shepherd-action 'root ('unload (symbol->string service)) result
201 result))
202
203(define (%load-file file)
204 "Load FILE in the Shepherd."
205 (with-shepherd-action 'root ('load file) result
206 result))
207
208(define (eval-there exp)
209 "Eval EXP in the Shepherd."
210 (with-shepherd-action 'root ('eval (object->string exp)) result
211 result))
212
213(define (load-services files)
214 "Load and register the services from FILES, where FILES contain code that
215returns a shepherd <service> object."
216 (eval-there `(register-services
217 ,@(map (lambda (file)
218 `(primitive-load ,file))
219 files))))
220
221(define (start-service name)
222 (with-shepherd-action name ('start) result
223 result))
224
225;; Local Variables:
226;; eval: (put 'alist-let* 'scheme-indent-function 2)
227;; eval: (put 'with-shepherd 'scheme-indent-function 1)
228;; eval: (put 'with-shepherd-action 'scheme-indent-function 3)
229;; End:
230
231;;; herd.scm ends here