1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2017 Ryan Moe <ryan.moe@gmail.com>
3 ;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
5 ;;; This file is part of GNU Guix.
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.
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.
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/>.
20 (define-module (gnu services virtualization)
21 #:use-module (gnu services)
22 #:use-module (gnu services configuration)
23 #:use-module (gnu services base)
24 #:use-module (gnu services dbus)
25 #:use-module (gnu services shepherd)
26 #:use-module (gnu system shadow)
27 #:use-module (gnu system file-systems)
28 #:use-module (gnu packages admin)
29 #:use-module (gnu packages virtualization)
30 #:use-module (guix records)
31 #:use-module (guix gexp)
32 #:use-module (guix packages)
33 #:use-module (srfi srfi-9)
34 #:use-module (srfi srfi-26)
35 #:use-module (rnrs bytevectors)
36 #:use-module (ice-9 match)
38 #:export (libvirt-configuration
48 qemu-binfmt-configuration
49 qemu-binfmt-configuration?
50 qemu-binfmt-service-type))
52 (define (uglify-field-name field-name)
53 (let ((str (symbol->string field-name)))
55 (string-split (string-delete #\? str) #\-)
58 (define (quote-val val)
59 (string-append "\"" val "\""))
61 (define (serialize-field field-name val)
62 (format #t "~a = ~a\n" (uglify-field-name field-name) val))
64 (define (serialize-string field-name val)
65 (serialize-field field-name (quote-val val)))
67 (define (serialize-boolean field-name val)
68 (serialize-field field-name (if val 1 0)))
70 (define (serialize-integer field-name val)
71 (serialize-field field-name val))
73 (define (build-opt-list val)
76 (string-join (map quote-val val) ",")
79 (define optional-list? list?)
80 (define optional-string? string?)
82 (define (serialize-list field-name val)
83 (serialize-field field-name (build-opt-list val)))
85 (define (serialize-optional-list field-name val)
87 (format #t "# ~a = []\n" (uglify-field-name field-name))
88 (serialize-list field-name val)))
90 (define (serialize-optional-string field-name val)
91 (if (string-null? val)
92 (format #t "# ~a = \"\"\n" (uglify-field-name field-name))
93 (serialize-string field-name val)))
95 (define-configuration libvirt-configuration
101 "Flag listening for secure TLS connections on the public TCP/IP port.
102 must set @code{listen} for this to have any effect.
104 It is necessary to setup a CA and issue server certificates before
105 using this capability.")
108 "Listen for unencrypted TCP connections on the public TCP/IP port.
109 must set @code{listen} for this to have any effect.
111 Using the TCP socket requires SASL authentication by default. Only
112 SASL mechanisms which support data encryption are allowed. This is
113 DIGEST_MD5 and GSSAPI (Kerberos5)")
116 "Port for accepting secure TLS connections This can be a port number,
120 "Port for accepting insecure TCP connections This can be a port number,
124 "IP address or hostname used for client connections.")
127 "Flag toggling mDNS advertisement of the libvirt service.
129 Alternatively can disable for all services on a host by
130 stopping the Avahi daemon.")
132 (string (string-append "Virtualization Host " (gethostname)))
133 "Default mDNS advertisement name. This must be unique on the
134 immediate broadcast network.")
137 "UNIX domain socket group ownership. This can be used to
138 allow a 'trusted' set of users access to management capabilities
139 without becoming root.")
142 "UNIX socket permissions for the R/O socket. This is used
143 for monitoring VM status only.")
146 "UNIX socket permissions for the R/W socket. Default allows
147 only root. If PolicyKit is enabled on the socket, the default
148 will change to allow everyone (eg, 0777)")
149 (unix-sock-admin-perms
151 "UNIX socket permissions for the admin socket. Default allows
152 only owner (root), do not change it unless you are sure to whom
153 you are exposing the access to.")
155 (string "/var/run/libvirt")
156 "The directory in which sockets will be found/created.")
159 "Authentication scheme for UNIX read-only sockets. By default
160 socket permissions allow anyone to connect")
163 "Authentication scheme for UNIX read-write sockets. By default
164 socket permissions only allow root. If PolicyKit support was compiled
165 into libvirt, the default will be to use 'polkit' auth.")
168 "Authentication scheme for TCP sockets. If you don't enable SASL,
169 then all TCP traffic is cleartext. Don't do this outside of a dev/test
173 "Authentication scheme for TLS sockets. TLS sockets already have
174 encryption provided by the TLS layer, and limited authentication is
175 done by certificates.
177 It is possible to make use of any SASL authentication mechanism as
178 well, by using 'sasl' for this option")
181 "API access control scheme.
183 By default an authenticated user is allowed access to all APIs. Access
184 drivers can place restrictions on this.")
187 "Server key file path. If set to an empty string, then no private key
191 "Server key file path. If set to an empty string, then no certificate
195 "Server key file path. If set to an empty string, then no CA certificate
199 "Certificate revocation list path. If set to an empty string, then no
203 "Disable verification of our own server certificates.
205 When libvirtd starts it performs some sanity checks against its own
209 "Disable verification of client certificates.
211 Client certificate verification is the primary authentication mechanism.
212 Any client which does not present a certificate signed by the CA
216 "Whitelist of allowed x509 Distinguished Name.")
217 (sasl-allowed-usernames
219 "Whitelist of allowed SASL usernames. The format for username
220 depends on the SASL authentication mechanism.")
223 "Override the compile time default TLS priority string. The
224 default is usually \"NORMAL\" unless overridden at build time.
225 Only set this is it is desired for libvirt to deviate from
226 the global default settings.")
229 "Maximum number of concurrent client connections to allow
230 over all sockets combined.")
233 "Maximum length of queue of connections waiting to be
234 accepted by the daemon. Note, that some protocols supporting
235 retransmission may obey this so that a later reattempt at
236 connection succeeds.")
237 (max-anonymous-clients
239 "Maximum length of queue of accepted but not yet authenticated
240 clients. Set this to zero to turn this feature off")
243 "Number of workers to start up initially.")
246 "Maximum number of worker threads.
248 If the number of active clients exceeds @code{min-workers},
249 then more threads are spawned, up to max_workers limit.
250 Typically you'd want max_workers to equal maximum number
251 of clients allowed.")
254 "Number of priority workers. If all workers from above
255 pool are stuck, some calls marked as high priority
256 (notably domainDestroy) can be executed in this pool.")
259 "Total global limit on concurrent RPC calls.")
262 "Limit on concurrent requests from a single client
263 connection. To avoid one client monopolizing the server
264 this should be a small fraction of the global max_requests
265 and max_workers parameter.")
268 "Same as @code{min-workers} but for the admin interface.")
271 "Same as @code{max-workers} but for the admin interface.")
274 "Same as @code{max-clients} but for the admin interface.")
275 (admin-max-queued-clients
277 "Same as @code{max-queued-clients} but for the admin interface.")
278 (admin-max-client-requests
280 "Same as @code{max-client-requests} but for the admin interface.")
283 "Logging level. 4 errors, 3 warnings, 2 information, 1 debug.")
285 (string "3:remote 4:event")
288 A filter allows to select a different logging level for a given category
290 The format for a filter is one of:
297 where @code{name} is a string which is matched against the category
298 given in the @code{VIR_LOG_INIT()} at the top of each libvirt source
299 file, e.g., \"remote\", \"qemu\", or \"util.json\" (the name in the
300 filter can be a substring of the full category name, in order
301 to match multiple similar categories), the optional \"+\" prefix
302 tells libvirt to log stack trace for each message matching
303 name, and @code{x} is the minimal level where matching messages should
313 Multiple filters can be defined in a single filters statement, they just
314 need to be separated by spaces.")
316 (string "3:syslog:libvirtd")
319 An output is one of the places to save logging information
320 The format for an output can be:
324 output goes to stderr
327 use syslog for the output and use the given name as the ident
329 @item x:file:file_path
330 output to a file, with the given filepath
333 output to journald logging system
336 In all case the x prefix is the minimal level, acting as a filter
345 Multiple outputs can be defined, they just need to be separated by spaces.")
348 "Allows usage of the auditing subsystem to be altered
351 @item 0: disable all auditing
352 @item 1: enable auditing, only if enabled on host
353 @item 2: enable auditing, and exit if disabled on host.
358 "Send audit messages via libvirt logging infrastructure.")
361 "Host UUID. UUID must not have all digits be the same.")
364 "Source to read host UUID.
368 @item @code{smbios}: fetch the UUID from @code{dmidecode -s system-uuid}
370 @item @code{machine-id}: fetch the UUID from @code{/etc/machine-id}
374 If @code{dmidecode} does not provide a valid UUID a temporary UUID
378 "A keepalive message is sent to a client after
379 @code{keepalive_interval} seconds of inactivity to check if
380 the client is still responding. If set to -1, libvirtd will
381 never send keepalive requests; however clients can still send
382 them and the daemon will send responses.")
385 "Maximum number of keepalive messages that are allowed to be sent
386 to the client without getting any response before the connection is
389 In other words, the connection is automatically
390 closed approximately after
391 @code{keepalive_interval * (keepalive_count + 1)} seconds since the last
392 message received from the client. When @code{keepalive-count} is
393 set to 0, connections will be automatically closed after
394 @code{keepalive-interval} seconds of inactivity without sending any
395 keepalive messages.")
396 (admin-keepalive-interval
398 "Same as above but for admin interface.")
399 (admin-keepalive-count
401 "Same as above but for admin interface.")
404 "Timeout for Open vSwitch calls.
406 The @code{ovs-vsctl} utility is used for the configuration and
407 its timeout option is set by default to 5 seconds to avoid
408 potential infinite waits blocking libvirt."))
410 (define* (libvirt-conf-file config)
411 "Return a libvirtd config file."
412 (plain-file "libvirtd.conf"
413 (with-output-to-string
415 (serialize-configuration config libvirt-configuration-fields)))))
417 (define %libvirt-accounts
418 (list (user-group (name "libvirt") (system? #t))))
420 (define (%libvirt-activation config)
421 (let ((sock-dir (libvirt-configuration-unix-sock-dir config)))
423 (use-modules (guix build utils))
424 (mkdir-p #$sock-dir))))
427 (define (libvirt-shepherd-service config)
428 (let* ((config-file (libvirt-conf-file config))
429 (libvirt (libvirt-configuration-libvirt config)))
430 (list (shepherd-service
431 (documentation "Run the libvirt daemon.")
432 (provision '(libvirtd))
433 (start #~(make-forkexec-constructor
434 (list (string-append #$libvirt "/sbin/libvirtd")
436 ;; For finding qemu and ip binaries.
437 #:environment-variables
439 "PATH=/run/current-system/profile/bin:"
440 "/run/current-system/profile/sbin"))))
441 (stop #~(make-kill-destructor))))))
443 (define libvirt-service-type
444 (service-type (name 'libvirt)
447 (service-extension polkit-service-type
448 (compose list libvirt-configuration-libvirt))
449 (service-extension profile-service-type
452 (libvirt-configuration-libvirt config)
454 (service-extension activation-service-type
456 (service-extension shepherd-root-service-type
457 libvirt-shepherd-service)
458 (service-extension account-service-type
459 (const %libvirt-accounts))))
460 (default-value (libvirt-configuration))))
463 (define-record-type* <virtlog-configuration>
464 virtlog-configuration make-virtlog-configuration
465 virtlog-configuration?
466 (libvirt virtlog-configuration-libvirt
468 (log-level virtlog-configuration-log-level
470 (log-filters virtlog-configuration-log-filters
471 (default "3:remote 4:event"))
472 (log-outputs virtlog-configuration-log-outputs
473 (default "3:syslog:virtlogd"))
474 (max-clients virtlog-configuration-max-clients
476 (max-size virtlog-configuration-max-size
477 (default 2097152)) ;; 2MB
478 (max-backups virtlog-configuration-max-backups
481 (define* (virtlogd-conf-file config)
482 "Return a virtlogd config file."
483 (plain-file "virtlogd.conf"
485 "log_level = " (number->string (virtlog-configuration-log-level config)) "\n"
486 "log_filters = \"" (virtlog-configuration-log-filters config) "\"\n"
487 "log_outputs = \"" (virtlog-configuration-log-outputs config) "\"\n"
488 "max_clients = " (number->string (virtlog-configuration-max-clients config)) "\n"
489 "max_size = " (number->string (virtlog-configuration-max-size config)) "\n"
490 "max_backups = " (number->string (virtlog-configuration-max-backups config)) "\n")))
492 (define (virtlogd-shepherd-service config)
493 (let* ((config-file (virtlogd-conf-file config))
494 (libvirt (virtlog-configuration-libvirt config)))
495 (list (shepherd-service
496 (documentation "Run the virtlog daemon.")
497 (provision '(virtlogd))
498 (start #~(make-forkexec-constructor
499 (list (string-append #$libvirt "/sbin/virtlogd")
500 "-f" #$config-file)))
501 (stop #~(make-kill-destructor))))))
503 (define virtlog-service-type
504 (service-type (name 'virtlogd)
507 (service-extension shepherd-root-service-type
508 virtlogd-shepherd-service)))
509 (default-value (virtlog-configuration))))
511 (define (generate-libvirt-documentation)
512 (generate-documentation
513 `((libvirt-configuration ,libvirt-configuration-fields))
514 'libvirt-configuration))
518 ;;; Transparent QEMU emulation via binfmt_misc.
521 ;; Platforms that QEMU can emulate.
522 (define-record-type <qemu-platform>
523 (qemu-platform name family magic mask)
525 (name qemu-platform-name) ;string
526 (family qemu-platform-family) ;string
527 (magic qemu-platform-magic) ;bytevector
528 (mask qemu-platform-mask)) ;bytevector
532 "Expand the given string into a bytevector."
535 (string? (syntax->datum #'str))
536 (let ((bv (u8-list->bytevector
538 (string->list (syntax->datum #'str))))))
541 ;;; The platform descriptions below are taken from
542 ;;; 'scripts/qemu-binfmt-conf.sh' in QEMU.
545 (qemu-platform "i386" "i386"
546 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00")
547 (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
550 (qemu-platform "i486" "i386"
551 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00")
552 (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
555 (qemu-platform "alpha" "alpha"
556 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90")
557 (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
560 (qemu-platform "arm" "arm"
561 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00")
562 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
565 (qemu-platform "armeb" "arm"
566 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28")
567 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
570 (qemu-platform "sparc" "sparc"
571 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02")
572 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
575 (qemu-platform "sparc32plus" "sparc"
576 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12")
577 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
580 (qemu-platform "ppc" "ppc"
581 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14")
582 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
585 (qemu-platform "ppc64" "ppc"
586 (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15")
587 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
590 (qemu-platform "ppc64le" "ppcle"
591 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00")
592 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00")))
595 (qemu-platform "m68k" "m68k"
596 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04")
597 (bv "\xff\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
599 ;; XXX: We could use the other endianness on a MIPS host.
601 (qemu-platform "mips" "mips"
602 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
603 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
606 (qemu-platform "mipsel" "mips"
607 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
608 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
611 (qemu-platform "mipsn32" "mips"
612 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
613 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
616 (qemu-platform "mipsn32el" "mips"
617 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
618 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
621 (qemu-platform "mips64" "mips"
622 (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
623 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
626 (qemu-platform "mips64el" "mips"
627 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
628 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
631 (qemu-platform "sh4" "sh4"
632 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00")
633 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
636 (qemu-platform "sh4eb" "sh4"
637 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a")
638 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
641 (qemu-platform "s390x" "s390x"
642 (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16")
643 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
646 (qemu-platform "aarch64" "arm"
647 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00")
648 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
651 (qemu-platform "hppa" "hppa"
652 (bv "\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f")
653 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
655 (define %qemu-platforms
656 (list %i386 %i486 %alpha %arm %sparc32plus %ppc %ppc64 %ppc64le %m68k
657 %mips %mipsel %mipsn32 %mipsn32el %mips64 %mips64el
658 %sh4 %sh4eb %s390x %aarch64 %hppa))
660 (define (lookup-qemu-platforms . names)
661 "Return the list of QEMU platforms that match NAMES--a list of names such as
662 \"arm\", \"hppa\", etc."
663 (filter (lambda (platform)
664 (member (qemu-platform-name platform) names))
667 (define-record-type* <qemu-binfmt-configuration>
668 qemu-binfmt-configuration make-qemu-binfmt-configuration
669 qemu-binfmt-configuration?
670 (qemu qemu-binfmt-configuration-qemu
672 (platforms qemu-binfmt-configuration-platforms
673 (default '())) ;safest default
674 (guix-support? qemu-binfmt-configuration-guix-support?
677 (define (qemu-platform->binfmt qemu platform)
678 "Return a gexp that evaluates to a binfmt string for PLATFORM, using the
680 (define (bytevector->binfmt-string bv)
681 ;; Return a binfmt-friendly string representing BV. Hex-encode every
682 ;; character, in particular because the doc notes "that you must escape
683 ;; any NUL bytes; parsing halts at the first one".
687 (string-pad (number->string n 16) 2 #\0)))
688 (bytevector->u8-list bv))))
691 (($ <qemu-platform> name family magic mask)
692 ;; See 'Documentation/binfmt_misc.txt' in the kernel.
693 #~(string-append ":qemu-" #$name ":M::"
694 #$(bytevector->binfmt-string magic)
695 ":" #$(bytevector->binfmt-string mask)
696 ":" #$(file-append qemu "/bin/qemu-" name)
700 (define %binfmt-mount-point
701 (file-system-mount-point %binary-format-file-system))
703 (define %binfmt-register-file
704 (string-append %binfmt-mount-point "/register"))
706 (define qemu-binfmt-shepherd-services
708 (($ <qemu-binfmt-configuration> qemu platforms)
709 (list (shepherd-service
710 (provision '(qemu-binfmt))
711 (documentation "Install binfmt_misc handlers for QEMU.")
712 (requirement '(file-system-/proc/sys/fs/binfmt_misc))
714 ;; Register the handlers for all of PLATFORMS.
715 (for-each (lambda (str)
716 (call-with-output-file
717 #$%binfmt-register-file
719 (display str port))))
721 #$@(map (cut qemu-platform->binfmt qemu
726 ;; Unregister the handlers.
727 (for-each (lambda (name)
728 (let ((file (string-append
729 #$%binfmt-mount-point
731 (call-with-output-file file
733 (display "-1" port)))))
734 '#$(map qemu-platform-name platforms))
737 (define qemu-binfmt-guix-chroot
739 ;; Add QEMU and its dependencies to the guix-daemon chroot so that our
740 ;; binfmt_misc handlers work in the chroot (otherwise 'execve' would fail
743 ;; The 'F' flag of binfmt_misc is meant to address this problem by loading
744 ;; the interpreter upfront rather than lazily, but apparently that is
745 ;; insufficient (perhaps it loads the 'qemu-ARCH' binary upfront but looks
746 ;; up its dependencies lazily?).
747 (($ <qemu-binfmt-configuration> qemu platforms guix?)
748 (if guix? (list qemu) '()))))
750 (define qemu-binfmt-service-type
751 ;; TODO: Make a separate binfmt_misc service out of this?
752 (service-type (name 'qemu-binfmt)
754 (list (service-extension file-system-service-type
756 (list %binary-format-file-system)))
757 (service-extension shepherd-root-service-type
758 qemu-binfmt-shepherd-services)
759 (service-extension guix-service-type
760 qemu-binfmt-guix-chroot)))
761 (default-value (qemu-binfmt-configuration))
763 "This service supports transparent emulation of binaries
764 compiled for other architectures using QEMU and the @code{binfmt_misc}
765 functionality of the kernel Linux.")))