1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2016 Alex Kost <alezost@gmail.com>
4 ;;; Copyright © 2016, 2017, 2018 Chris Marusich <cmmarusich@gmail.com>
5 ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
6 ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
8 ;;; This file is part of GNU Guix.
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.
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.
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/>.
23 (define-module (guix scripts system)
24 #:use-module (guix config)
25 #:use-module (guix ui)
26 #:use-module ((guix status) #:select (with-status-verbosity))
27 #:use-module (guix store)
28 #:autoload (guix store database) (register-path)
29 #:use-module (guix grafts)
30 #:use-module (guix gexp)
31 #:use-module (guix derivations)
32 #:use-module (guix packages)
33 #:use-module (guix utils)
34 #:use-module (guix monads)
35 #:use-module (guix records)
36 #:use-module (guix profiles)
37 #:use-module (guix scripts)
38 #:use-module (guix scripts build)
39 #:autoload (guix scripts package) (delete-generations
40 delete-matching-generations)
41 #:use-module (guix graph)
42 #:use-module (guix scripts graph)
43 #:use-module (guix build utils)
44 #:use-module (guix progress)
45 #:use-module ((guix build syscalls) #:select (terminal-columns))
46 #:use-module (gnu build install)
47 #:autoload (gnu build file-systems)
48 (find-partition-by-label find-partition-by-uuid)
49 #:autoload (gnu build linux-modules)
50 (device-module-aliases matching-modules)
51 #:use-module (gnu system linux-initrd)
52 #:use-module (gnu system)
53 #:use-module (gnu bootloader)
54 #:use-module (gnu system file-systems)
55 #:use-module (gnu system mapped-devices)
56 #:use-module (gnu system linux-container)
57 #:use-module (gnu system uuid)
58 #:use-module (gnu system vm)
59 #:use-module (gnu services)
60 #:use-module (gnu services shepherd)
61 #:use-module (gnu services herd)
62 #:use-module (srfi srfi-1)
63 #:use-module (srfi srfi-11)
64 #:use-module (srfi srfi-19)
65 #:use-module (srfi srfi-26)
66 #:use-module (srfi srfi-34)
67 #:use-module (srfi srfi-35)
68 #:use-module (srfi srfi-37)
69 #:use-module (ice-9 match)
70 #:use-module (rnrs bytevectors)
72 read-operating-system))
76 ;;; Operating system declaration.
80 ;; Module in which the machine description file is loaded.
81 (make-user-module '((gnu system)
83 (gnu system shadow))))
85 (define (read-operating-system file)
86 "Read the operating-system declaration from FILE and return it."
87 (load* file %user-module))
94 (define-syntax-rule (save-load-path-excursion body ...)
95 "Save the current values of '%load-path' and '%load-compiled-path', run
96 BODY..., and restore them."
97 (let ((path %load-path)
98 (cpath %load-compiled-path))
104 (set! %load-path path)
105 (set! %load-compiled-path cpath)))))
107 (define-syntax-rule (save-environment-excursion body ...)
108 "Save the current environment variables, run BODY..., and restore them."
109 (let ((env (environ)))
117 (define topologically-sorted*
118 (store-lift topologically-sorted))
121 (define* (copy-item item references target
122 #:key (log-port (current-error-port)))
123 "Copy ITEM to the store under root directory TARGET and register it with
124 REFERENCES as its set of references."
125 (let ((dest (string-append target item))
126 (state (string-append target "/var/guix")))
127 (format log-port "copying '~a'...~%" item)
129 ;; Remove DEST if it exists to make sure that (1) we do not fail badly
130 ;; while trying to overwrite it (see <http://bugs.gnu.org/20722>), and
131 ;; (2) we end up with the right contents.
132 (when (false-if-exception (lstat dest))
133 (for-each make-file-writable
134 (find-files dest (lambda (file stat)
135 (eq? 'directory (stat:type stat)))
137 (delete-file-recursively dest))
139 (copy-recursively item dest
140 #:log (%make-void-port "w"))
142 ;; Register ITEM; as a side-effect, it resets timestamps, etc.
143 ;; Explicitly use "TARGET/var/guix" as the state directory, to avoid
144 ;; reproducing the user's current settings; see
145 ;; <http://bugs.gnu.org/18049>.
146 (unless (register-path item
148 #:state-directory state
149 #:references references)
150 (leave (G_ "failed to register '~a' under '~a'~%")
153 (define* (copy-closure item target
154 #:key (log-port (current-error-port)))
155 "Copy ITEM and all its dependencies to the store under root directory
156 TARGET, and register them."
157 (mlet* %store-monad ((to-copy (topologically-sorted* (list item)))
158 (refs (mapm %store-monad references* to-copy))
159 (info (mapm %store-monad query-path-info*
161 (append to-copy (concatenate refs)))))
162 (size -> (reduce + 0 (map path-info-nar-size info))))
164 (progress-reporter/bar (length to-copy)
165 (format #f (G_ "copying to '~a'...")
168 (check-available-space size target)
170 (call-with-progress-reporter progress-bar
172 (let ((void (%make-void-port "w")))
173 (for-each (lambda (item refs)
174 (copy-item item refs target #:log-port void)
178 (return *unspecified*)))
180 (define* (install-bootloader installer
184 "Run INSTALLER, a bootloader installation script, with error handling, in
186 (mlet %store-monad ((installer-drv (if installer
187 (lower-object installer)
189 (bootcfg (lower-object bootcfg)))
190 (let* ((gc-root (string-append target %gc-roots-directory
192 (temp-gc-root (string-append gc-root ".new"))
193 (install (and installer-drv
194 (derivation->output-path installer-drv)))
195 (bootcfg (derivation->output-path bootcfg)))
196 ;; Prepare the symlink to bootloader config file to make sure that it's
197 ;; a GC root when 'installer-drv' completes (being a bit paranoid.)
198 (switch-symlinks temp-gc-root bootcfg)
200 (unless (false-if-exception
202 (install-boot-config bootcfg bootcfg-file target)
204 (save-load-path-excursion (primitive-load install)))))
205 (delete-file temp-gc-root)
206 (leave (G_ "failed to install bootloader ~a~%") install))
208 ;; Register bootloader config file as a GC root so that its dependencies
209 ;; (background image, font, etc.) are not reclaimed.
210 (rename-file temp-gc-root gc-root)
213 (define* (install os-drv target
214 #:key (log-port (current-output-port))
215 bootloader-installer install-bootloader?
216 bootcfg bootcfg-file)
217 "Copy the closure of BOOTCFG, which includes the output of OS-DRV, to
218 directory TARGET. TARGET must be an absolute directory name since that's what
219 'register-path' expects.
221 When INSTALL-BOOTLOADER? is true, install bootloader using BOOTCFG."
222 (define (maybe-copy to-copy)
223 (with-monad %store-monad
224 (if (string=? target "/")
226 (warning (G_ "initializing the current root file system~%"))
229 ;; Make sure the target store exists.
230 (mkdir-p (string-append target (%store-prefix)))
232 ;; Copy items to the new store.
233 (copy-closure to-copy target #:log-port log-port)))))
235 ;; Make sure TARGET is root-owned when running as root, but still allow
236 ;; non-root uses (useful for testing.) See
237 ;; <http://lists.gnu.org/archive/html/guix-devel/2015-05/msg00452.html>.
238 (if (zero? (geteuid))
240 (warning (G_ "not running as 'root', so \
241 the ownership of '~a' may be incorrect!~%")
244 ;; If a previous installation was attempted, make sure we start anew; in
245 ;; particular, we don't want to keep a store database that might not
246 ;; correspond to what we're actually putting in the store.
247 (let ((state (string-append target "/var/guix")))
248 (when (file-exists? state)
249 (delete-file-recursively state)))
252 (let ((os-dir (derivation->output-path os-drv))
253 (format (lift format %store-monad))
254 (populate (lift2 populate-root-file-system %store-monad)))
256 (mlet %store-monad ((bootcfg (lower-object bootcfg)))
258 ;; Copy the closure of BOOTCFG, which includes OS-DIR,
259 ;; eventual background image and so on.
260 (maybe-copy (derivation->output-path bootcfg))
262 ;; Create a bunch of additional files.
263 (format log-port "populating '~a'...~%" target)
264 (populate os-dir target)
266 (mwhen install-bootloader?
267 (install-bootloader bootloader-installer
269 #:bootcfg-file bootcfg-file
270 #:target target))))))
277 (define %system-profile
278 ;; The system profile.
279 (string-append %state-directory "/profiles/system"))
281 (define-syntax-rule (with-shepherd-error-handling mbody ...)
282 "Catch and report Shepherd errors that arise when binding MBODY, a monadic
283 expression in %STORE-MONAD."
287 (guard (c ((shepherd-error? c)
288 (values (report-shepherd-error c) store)))
289 (values (run-with-store store (begin mbody ...))
291 (lambda (key proc format-string format-args errno . rest)
292 (warning (G_ "while talking to shepherd: ~a~%")
293 (apply format #f format-string format-args))
294 (values #f store)))))
296 (define (report-shepherd-error error)
297 "Report ERROR, a '&shepherd-error' error condition object."
298 (cond ((service-not-found-error? error)
299 (report-error (G_ "service '~a' could not be found~%")
300 (service-not-found-error-service error)))
301 ((action-not-found-error? error)
302 (report-error (G_ "service '~a' does not have an action '~a'~%")
303 (action-not-found-error-service error)
304 (action-not-found-error-action error)))
305 ((action-exception-error? error)
306 (report-error (G_ "exception caught while executing '~a' \
308 (action-exception-error-action error)
309 (action-exception-error-service error))
310 (print-exception (current-error-port) #f
311 (action-exception-error-key error)
312 (action-exception-error-arguments error)))
313 ((unknown-shepherd-error? error)
314 (report-error (G_ "something went wrong: ~s~%")
315 (unknown-shepherd-error-sexp error)))
316 ((shepherd-error? error)
317 (report-error (G_ "shepherd error~%")))
318 ((not error) ;not an error
321 (define (call-with-service-upgrade-info new-services mproc)
322 "Call MPROC, a monadic procedure in %STORE-MONAD, passing it the list of
323 names of services to load (upgrade), and the list of names of services to
325 (match (current-services)
327 (let-values (((to-unload to-restart)
328 (shepherd-service-upgrade services new-services)))
330 (map (compose first live-service-provision)
333 (with-monad %store-monad
334 (warning (G_ "failed to obtain list of shepherd services~%"))
337 (define (upgrade-shepherd-services os)
338 "Upgrade the Shepherd (PID 1) by unloading obsolete services and loading new
339 services specified in OS and not currently running.
341 This is currently very conservative in that it does not stop or unload any
342 running service. Unloading or stopping the wrong service ('udev', say) could
343 bring the system down."
346 (fold-services (operating-system-services os)
347 #:target-type shepherd-root-service-type)))
349 ;; Arrange to simply emit a warning if the service upgrade fails.
350 (with-shepherd-error-handling
351 (call-with-service-upgrade-info new-services
352 (lambda (to-restart to-unload)
353 (for-each (lambda (unload)
354 (info (G_ "unloading service '~a'...~%") unload)
355 (unload-service unload))
358 (with-monad %store-monad
359 (munless (null? new-services)
360 (let ((new-service-names (map shepherd-service-canonical-name new-services))
361 (to-restart-names (map shepherd-service-canonical-name to-restart))
362 (to-start (filter shepherd-service-auto-start? new-services)))
363 (info (G_ "loading new services:~{ ~a~}...~%") new-service-names)
364 (unless (null? to-restart-names)
365 ;; Listing TO-RESTART-NAMES in the message below wouldn't help
366 ;; because many essential services cannot be meaningfully
367 ;; restarted. See <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22039#30>.
368 (format #t (G_ "To complete the upgrade, run 'herd restart SERVICE' to stop,
369 upgrade, and restart each service that was not automatically restarted.\n")))
370 (mlet %store-monad ((files (mapm %store-monad
371 (compose lower-object
372 shepherd-service-file)
374 ;; Here we assume that FILES are exactly those that were computed
375 ;; as part of the derivation that built OS, which is normally the
377 (load-services/safe (map derivation->output-path files))
379 (for-each start-service
380 (map shepherd-service-canonical-name to-start))
383 (define* (switch-to-system os
384 #:optional (profile %system-profile))
385 "Make a new generation of PROFILE pointing to the directory of OS, switch to
386 it atomically, and then run OS's activation script."
387 (mlet* %store-monad ((drv (operating-system-derivation os))
388 (script (lower-object (operating-system-activation-script os))))
389 (let* ((system (derivation->output-path drv))
390 (number (+ 1 (generation-number profile)))
391 (generation (generation-file-name profile number)))
392 (switch-symlinks generation system)
393 (switch-symlinks profile generation)
395 (format #t (G_ "activating system...~%"))
397 ;; The activation script may change $PATH, among others, so protect
399 (save-environment-excursion
400 ;; Tell 'activate-current-system' what the new system is.
401 (setenv "GUIX_NEW_SYSTEM" system)
403 ;; The activation script may modify '%load-path' & co., so protect
404 ;; against that. This is necessary to ensure that
405 ;; 'upgrade-shepherd-services' gets to see the right modules when it
406 ;; computes derivations with 'gexp->derivation'.
407 (save-load-path-excursion
408 (primitive-load (derivation->output-path script))))
410 ;; Finally, try to update system services.
411 (upgrade-shepherd-services os))))
413 (define-syntax-rule (unless-file-not-found exp)
418 (if (= ENOENT (system-error-errno args))
420 (apply throw args)))))
422 (define (seconds->string seconds)
423 "Return a string representing the date for SECONDS."
424 (let ((time (make-time time-utc 0 seconds)))
425 (date->string (time-utc->date time)
428 (define* (profile-boot-parameters #:optional (profile %system-profile)
430 (reverse (generation-numbers profile))))
431 "Return a list of 'boot-parameters' for the generations of PROFILE specified
432 by NUMBERS, which is a list of generation numbers. The list is ordered from
433 the most recent to the oldest profiles."
434 (define (system->boot-parameters system number time)
435 (unless-file-not-found
436 (let* ((params (read-boot-parameters-file system))
437 (label (boot-parameters-label params)))
440 (label (string-append label " (#"
441 (number->string number) ", "
442 (seconds->string time) ")"))))))
443 (let* ((systems (map (cut generation-file-name profile <>)
445 (times (map (lambda (system)
446 (unless-file-not-found
447 (stat:mtime (lstat system))))
449 (filter-map system->boot-parameters systems numbers times)))
455 (define (roll-back-system store)
456 "Roll back the system profile to its previous generation. STORE is an open
457 connection to the store."
458 (switch-to-system-generation store "-1"))
462 ;;; Switch generations.
464 (define (switch-to-system-generation store spec)
465 "Switch the system profile to the generation specified by SPEC, and
466 re-install bootloader with a configuration file that uses the specified system
467 generation as its default entry. STORE is an open connection to the store."
468 (let ((number (relative-generation-spec->number %system-profile spec)))
471 (reinstall-bootloader store number)
472 (switch-to-generation* %system-profile number))
473 (leave (G_ "cannot switch to system generation '~a'~%") spec))))
475 (define* (system-bootloader-name #:optional (system %system-profile))
476 "Return the bootloader name stored in SYSTEM's \"parameters\" file."
477 (let ((params (unless-file-not-found
478 (read-boot-parameters-file system))))
479 (boot-parameters-bootloader-name params)))
481 (define (reinstall-bootloader store number)
482 "Re-install bootloader for existing system profile generation NUMBER.
483 STORE is an open connection to the store."
484 (let* ((generation (generation-file-name %system-profile number))
485 ;; Detect the bootloader used in %system-profile.
486 (bootloader (lookup-bootloader-by-name (system-bootloader-name)))
488 ;; Use the detected bootloader with default configuration.
489 ;; It will be enough to allow the system to boot.
490 (bootloader-config (bootloader-configuration
491 (bootloader bootloader)))
493 ;; Make the specified system generation the default entry.
494 (params (profile-boot-parameters %system-profile (list number)))
496 (delv number (reverse (generation-numbers %system-profile))))
497 (old-params (profile-boot-parameters
498 %system-profile old-generations))
499 (entries (map boot-parameters->menu-entry params))
500 (old-entries (map boot-parameters->menu-entry old-params)))
501 (run-with-store store
503 ((bootcfg (lower-object
504 ((bootloader-configuration-file-generator bootloader)
505 bootloader-config entries
506 #:old-entries old-entries)))
507 (bootcfg-file -> (bootloader-configuration-file bootloader))
509 (drvs -> (list bootcfg)))
511 (show-what-to-build* drvs)
512 (built-derivations drvs)
513 ;; Only install bootloader configuration file. Thus, no installer is
515 (install-bootloader #f
517 #:bootcfg-file bootcfg-file
518 #:target target))))))
525 (define (service-node-label service)
526 "Return a label to represent SERVICE."
527 (let ((type (service-kind service))
528 (value (service-value service)))
529 (string-append (symbol->string (service-type-name type))
530 (cond ((or (number? value) (symbol? value))
531 (string-append " " (object->string value)))
533 (string-append " " value))
534 ((file-system? value)
535 (string-append " " (file-system-mount-point value)))
539 (define (service-node-type services)
540 "Return a node type for SERVICES. Since <service> instances are not
541 self-contained (they express dependencies on service types, not on services),
542 we have to create the 'edges' procedure dynamically as a function of the full
546 (description "the DAG of services")
547 (identifier (lift1 object-address %store-monad))
548 (label service-node-label)
549 (edges (lift1 (service-back-edges services) %store-monad))))
551 (define (shepherd-service-node-label service)
552 "Return a label for a node representing a <shepherd-service>."
553 (string-join (map symbol->string (shepherd-service-provision service))))
555 (define (shepherd-service-node-type services)
556 "Return a node type for SERVICES, a list of <shepherd-service>."
558 (name "shepherd-service")
559 (description "the dependency graph of shepherd services")
560 (identifier (lift1 shepherd-service-node-label %store-monad))
561 (label shepherd-service-node-label)
562 (edges (lift1 (shepherd-service-back-edges services) %store-monad))))
569 (define* (display-system-generation number
570 #:optional (profile %system-profile))
571 "Display a summary of system generation NUMBER in a human-readable format."
572 (unless (zero? number)
573 (let* ((generation (generation-file-name profile number))
574 (params (read-boot-parameters-file generation))
575 (label (boot-parameters-label params))
576 (bootloader-name (boot-parameters-bootloader-name params))
577 (root (boot-parameters-root-device params))
578 (root-device (if (bytevector? root)
581 (kernel (boot-parameters-kernel params)))
582 (display-generation profile number)
583 (format #t (G_ " file name: ~a~%") generation)
584 (format #t (G_ " canonical file name: ~a~%") (readlink* generation))
585 ;; TRANSLATORS: Please preserve the two-space indentation.
586 (format #t (G_ " label: ~a~%") label)
587 (format #t (G_ " bootloader: ~a~%") bootloader-name)
589 ;; TRANSLATORS: The '~[', '~;', and '~]' sequences in this string must
590 ;; be preserved. They denote conditionals, such that the result will
592 ;; root device: UUID: 12345-678
594 ;; root device: label: "my-root"
596 ;; root device: /dev/sda3
597 (format #t (G_ " root device: ~[UUID: ~a~;label: ~s~;~a~]~%")
598 (cond ((uuid? root-device) 0)
599 ((file-system-label? root-device) 1)
601 (cond ((uuid? root-device)
602 (uuid->string root-device))
603 ((file-system-label? root-device)
604 (file-system-label->string root-device))
608 (format #t (G_ " kernel: ~a~%") kernel))))
610 (define* (list-generations pattern #:optional (profile %system-profile))
611 "Display in a human-readable format all the system generations matching
612 PATTERN, a string. When PATTERN is #f, display all the system generations."
613 (cond ((not (file-exists? profile)) ; XXX: race condition
614 (raise (condition (&profile-not-found-error
615 (profile profile)))))
616 ((string-null? pattern)
617 (for-each display-system-generation (profile-generations profile)))
618 ((matching-generations pattern profile)
621 (if (null-list? numbers)
624 (for-each display-system-generation numbers)))))
626 (leave (G_ "invalid syntax: ~a~%") pattern))))
630 ;;; File system declaration checks.
633 (define (check-file-system-availability file-systems)
634 "Check whether the UUIDs or partition labels that FILE-SYSTEMS refer to, if
635 any, are available. Raise an error if they're not."
638 (and (file-system-mount? fs)
639 (not (member (file-system-type fs)
640 %pseudo-file-system-types))
641 (not (memq 'bind-mount (file-system-flags fs)))))
646 (file-system-label? (file-system-device fs)))
651 (string? (file-system-device fs)))
656 (uuid? (file-system-device fs)))
661 (define (file-system-location* fs)
663 (source-properties->location
664 (file-system-location fs))))
666 (let-syntax ((error (syntax-rules ()
670 (format (current-error-port)
672 (for-each (lambda (fs)
675 (stat (file-system-device fs)))
677 (let ((errno (system-error-errno args))
678 (device (file-system-device fs)))
679 (error (G_ "~a: error: device '~a' not found: ~a~%")
680 (file-system-location* fs) device
682 (unless (string-prefix? "/" device)
683 (display-hint (format #f (G_ "If '~a' is a file system
684 label, write @code{(file-system-label ~s)} in your @code{device} field.")
687 (for-each (lambda (fs)
688 (let ((label (file-system-label->string
689 (file-system-device fs))))
690 (unless (find-partition-by-label label)
691 (error (G_ "~a: error: file system with label '~a' not found~%")
692 (file-system-location* fs) label))))
694 (for-each (lambda (fs)
695 (unless (find-partition-by-uuid (file-system-device fs))
696 (error (G_ "~a: error: file system with UUID '~a' not found~%")
697 (file-system-location* fs)
698 (uuid->string (file-system-device fs)))))
702 ;; Better be safe than sorry.
705 (define (check-mapped-devices os)
706 "Check that each of MAPPED-DEVICES is valid according to the 'check'
707 procedure of its type."
708 (define boot-mapped-devices
709 (operating-system-boot-mapped-devices os))
711 (define (needed-for-boot? md)
712 (memq md boot-mapped-devices))
714 (define initrd-modules
715 (operating-system-initrd-modules os))
717 (for-each (lambda (md)
718 (let ((check (mapped-device-kind-check
719 (mapped-device-type md))))
720 ;; We expect CHECK to raise an exception with a detailed
721 ;; '&message' if something goes wrong.
723 #:needed-for-boot? (needed-for-boot? md)
724 #:initrd-modules initrd-modules)))
725 (operating-system-mapped-devices os)))
727 (define (check-initrd-modules os)
728 "Check that modules needed by 'needed-for-boot' file systems in OS are
729 available in the initrd. Note that mapped devices are responsible for
730 checking this by themselves in their 'check' procedure."
731 (define (file-system-/dev fs)
732 (let ((device (file-system-device fs)))
737 (find-partition-by-uuid device))
738 ((? file-system-label?)
739 (find-partition-by-label (file-system-label->string device))))))
742 (filter file-system-needed-for-boot?
743 (operating-system-file-systems os)))
745 (for-each (lambda (fs)
746 (check-device-initrd-modules (file-system-/dev fs)
747 (operating-system-initrd-modules os)
748 (source-properties->location
749 (file-system-location fs))))
757 (define* (system-derivation-for-action os action
758 #:key image-size file-system-type
760 "Return as a monadic value the derivation for OS according to ACTION."
762 ((build init reconfigure)
763 (operating-system-derivation os))
765 (container-script os #:mappings mappings))
767 (system-qemu-image os #:disk-image-size image-size))
769 (system-qemu-image/shared-store-script os
770 #:full-boot? full-boot?
775 #:mappings mappings))
777 (system-disk-image os
778 #:name (match file-system-type
779 ("iso9660" "image.iso")
781 #:disk-image-size image-size
782 #:file-system-type file-system-type))
784 (system-docker-image os #:register-closures? #t))))
786 (define (maybe-suggest-running-guix-pull)
787 "Suggest running 'guix pull' if this has never been done before."
788 ;; The reason for this is that the 'guix' binding that we see here comes
789 ;; from either ~/.config/latest or, if it's missing, from the
790 ;; globally-installed Guix, which is necessarily older. See
791 ;; <http://lists.gnu.org/archive/html/guix-devel/2014-08/msg00057.html> for
794 (string-append (config-directory) "/current"))
796 (unless (file-exists? latest)
797 (warning (G_ "~a not found: 'guix pull' was never run~%") latest)
798 (warning (G_ "Consider running 'guix pull' before 'reconfigure'.~%"))
799 (warning (G_ "Failing to do that may downgrade your system!~%"))))
801 (define (bootloader-installer-script installer
802 bootloader device target)
803 "Return a file calling INSTALLER gexp with given BOOTLOADER, DEVICE
804 and TARGET arguments."
805 (scheme-file "bootloader-installer"
806 (with-imported-modules '((gnu build bootloader)
809 (use-modules (gnu build bootloader)
815 (guard (c ((message-condition? c) ;XXX: i18n
816 (format (current-error-port) "error: ~a~%"
817 (condition-message c))
819 (#$installer #$bootloader #$device #$target)
820 (format #t "bootloader successfully installed on '~a'~%"
823 (define* (perform-action action os
824 #:key skip-safety-checks?
826 dry-run? derivations-only?
827 use-substitutes? bootloader-target target
828 image-size file-system-type full-boot?
831 "Perform ACTION for OS. INSTALL-BOOTLOADER? specifies whether to install
832 bootloader; BOOTLOADER-TAGET is the target for the bootloader; TARGET is the
833 target root directory; IMAGE-SIZE is the size of the image to be built, for
834 the 'vm-image' and 'disk-image' actions. The root file system is created as a
835 FILE-SYSTEM-TYPE file system. FULL-BOOT? is used for the 'vm' action; it
836 determines whether to boot directly to the kernel or to the bootloader.
838 When DERIVATIONS-ONLY? is true, print the derivation file name(s) without
841 When GC-ROOT is a path, also make that path an indirect root of the build
842 output when building a system derivation, such as a disk image.
844 When SKIP-SAFETY-CHECKS? is true, skip the file system and initrd module
847 (cut format #t "~a~%" <>))
850 (if (eq? 'init action)
852 (map boot-parameters->menu-entry (profile-boot-parameters))))
855 (bootloader-configuration-bootloader (operating-system-bootloader os)))
858 (and (not (eq? 'container action))
859 (operating-system-bootcfg os menu-entries)))
861 (define bootloader-script
862 (let ((installer (bootloader-installer bootloader))
863 (target (or target "/")))
864 (bootloader-installer-script installer
865 (bootloader-package bootloader)
866 bootloader-target target)))
868 (when (eq? action 'reconfigure)
869 (maybe-suggest-running-guix-pull))
871 ;; Check whether the declared file systems exist. This is better than
872 ;; instantiating a broken configuration. Assume that we can only check if
874 (when (and (not skip-safety-checks?)
875 (memq action '(init reconfigure)))
876 (check-mapped-devices os)
877 (when (zero? (getuid))
878 (check-file-system-availability (operating-system-file-systems os))
879 (check-initrd-modules os)))
882 ((sys (system-derivation-for-action os action
883 #:file-system-type file-system-type
884 #:image-size image-size
885 #:full-boot? full-boot?
886 #:mappings mappings))
888 ;; For 'init' and 'reconfigure', always build BOOTCFG, even if
889 ;; --no-bootloader is passed, because we then use it as a GC root.
890 ;; See <http://bugs.gnu.org/21068>.
891 (drvs (mapm %store-monad lower-object
892 (if (memq action '(init reconfigure))
893 (if install-bootloader?
894 (list sys bootcfg bootloader-script)
897 (% (if derivations-only?
898 (return (for-each (compose println derivation-file-name)
900 (maybe-build drvs #:dry-run? dry-run?
901 #:use-substitutes? use-substitutes?))))
903 (if (or dry-run? derivations-only?)
905 (let ((bootcfg-file (bootloader-configuration-file bootloader)))
906 (for-each (compose println derivation->output-path)
912 (switch-to-system os)
913 (mwhen install-bootloader?
914 (install-bootloader bootloader-script
916 #:bootcfg-file bootcfg-file
920 (format #t (G_ "initializing operating system under '~a'...~%")
922 (install sys (canonicalize-path target)
923 #:install-bootloader? install-bootloader?
925 #:bootcfg-file bootcfg-file
926 #:bootloader-installer bootloader-script))
928 ;; All we had to do was to build SYS and maybe register an
930 (let ((output (derivation->output-path sys)))
933 (register-root* (list output) gc-root))
934 (return output)))))))))
936 (define (export-extension-graph os port)
937 "Export the service extension graph of OS to PORT."
938 (let* ((services (operating-system-services os))
939 (system (find (lambda (service)
940 (eq? (service-kind service) system-service-type))
942 (export-graph (list system) (current-output-port)
943 #:node-type (service-node-type services)
944 #:reverse-edges? #t)))
946 (define (export-shepherd-graph os port)
947 "Export the graph of shepherd services of OS to PORT."
948 (let* ((services (operating-system-services os))
949 (pid1 (fold-services services
950 #:target-type shepherd-root-service-type))
951 (shepherds (service-value pid1)) ;list of <shepherd-service>
952 (sinks (filter (lambda (service)
953 (null? (shepherd-service-requirement service)))
955 (export-graph sinks (current-output-port)
956 #:node-type (shepherd-service-node-type shepherds)
957 #:reverse-edges? #t)))
965 (display (G_ "Usage: guix system [OPTION ...] ACTION [ARG ...] [FILE]
966 Build the operating system declared in FILE according to ACTION.
967 Some ACTIONS support additional ARGS.\n"))
969 (display (G_ "The valid values for ACTION are:\n"))
972 search search for existing service types\n"))
974 reconfigure switch to a new operating system configuration\n"))
976 roll-back switch to the previous operating system configuration\n"))
978 list-generations list the system generations\n"))
980 switch-generation switch to an existing operating system configuration\n"))
982 delete-generations delete old system generations\n"))
984 build build the operating system without installing anything\n"))
986 container build a container that shares the host's store\n"))
988 vm build a virtual machine image that shares the host's store\n"))
990 vm-image build a freestanding virtual machine image\n"))
992 disk-image build a disk image, suitable for a USB stick\n"))
994 docker-image build a Docker image\n"))
996 init initialize a root file system to run GNU\n"))
998 extension-graph emit the service extension graph in Dot format\n"))
1000 shepherd-graph emit the graph of shepherd services in Dot format\n"))
1002 (show-build-options-help)
1004 -d, --derivation return the derivation of the given system"))
1006 -e, --expression=EXPR consider the operating-system EXPR evaluates to
1007 instead of reading FILE, when applicable"))
1010 apply STRATEGY (one of nothing-special, backtrace,
1011 or debug) when an error occurs while reading FILE"))
1013 --file-system-type=TYPE
1014 for 'disk-image', produce a root file system of TYPE
1015 (one of 'ext4', 'iso9660')"))
1017 --image-size=SIZE for 'vm-image', produce an image of SIZE"))
1019 --no-bootloader for 'init', do not install a bootloader"))
1021 --share=SPEC for 'vm', share host file system according to SPEC"))
1023 -r, --root=FILE for 'vm', 'vm-image', 'disk-image', 'container',
1024 and 'build', make FILE a symlink to the result, and
1025 register it as a garbage collector root"))
1027 --expose=SPEC for 'vm', expose host file system according to SPEC"))
1029 --full-boot for 'vm', make a full boot sequence"))
1031 --skip-checks skip file system and initrd module safety checks"))
1033 -v, --verbosity=LEVEL use the given verbosity LEVEL"))
1036 -h, --help display this help and exit"))
1038 -V, --version display version information and exit"))
1040 (show-bug-report-information))
1043 ;; Specifications of the command-line options.
1044 (cons* (option '(#\h "help") #f #f
1048 (option '(#\V "version") #f #f
1050 (show-version-and-exit "guix system")))
1051 (option '(#\e "expression") #t #f
1052 (lambda (opt name arg result)
1053 (alist-cons 'expression arg result)))
1054 (option '(#\d "derivation") #f #f
1055 (lambda (opt name arg result)
1056 (alist-cons 'derivations-only? #t result)))
1057 (option '("on-error") #t #f
1058 (lambda (opt name arg result)
1059 (alist-cons 'on-error (string->symbol arg)
1061 (option '(#\t "file-system-type") #t #f
1062 (lambda (opt name arg result)
1063 (alist-cons 'file-system-type arg
1065 (option '("image-size") #t #f
1066 (lambda (opt name arg result)
1067 (alist-cons 'image-size (size->number arg)
1069 (option '("no-bootloader" "no-grub") #f #f
1070 (lambda (opt name arg result)
1071 (alist-cons 'install-bootloader? #f result)))
1072 (option '("full-boot") #f #f
1073 (lambda (opt name arg result)
1074 (alist-cons 'full-boot? #t result)))
1075 (option '("skip-checks") #f #f
1076 (lambda (opt name arg result)
1077 (alist-cons 'skip-safety-checks? #t result)))
1079 (option '("share") #t #f
1080 (lambda (opt name arg result)
1081 (alist-cons 'file-system-mapping
1082 (specification->file-system-mapping arg #t)
1084 (option '("expose") #t #f
1085 (lambda (opt name arg result)
1086 (alist-cons 'file-system-mapping
1087 (specification->file-system-mapping arg #f)
1090 (option '(#\n "dry-run") #f #f
1091 (lambda (opt name arg result)
1092 (alist-cons 'dry-run? #t (alist-cons 'graft? #f result))))
1093 (option '(#\v "verbosity") #t #f
1094 (lambda (opt name arg result)
1095 (let ((level (string->number* arg)))
1096 (alist-cons 'verbosity level
1097 (alist-delete 'verbosity result)))))
1098 (option '(#\s "system") #t #f
1099 (lambda (opt name arg result)
1100 (alist-cons 'system arg
1101 (alist-delete 'system result eq?))))
1102 (option '(#\r "root") #t #f
1103 (lambda (opt name arg result)
1104 (alist-cons 'gc-root arg result)))
1105 %standard-build-options))
1107 (define %default-options
1108 ;; Alist of default option values.
1109 `((system . ,(%current-system))
1112 (print-build-trace? . #t)
1113 (print-extended-build-trace? . #t)
1114 (multiplexed-build-output? . #t)
1117 (verbosity . #f) ;default
1118 (file-system-type . "ext4")
1119 (image-size . guess)
1120 (install-bootloader? . #t)))
1127 (define (process-action action args opts)
1128 "Process ACTION, a sub-command, with the arguments are listed in ARGS.
1129 ACTION must be one of the sub-commands that takes an operating system
1130 declaration as an argument (a file name.) OPTS is the raw alist of options
1131 resulting from command-line parsing."
1132 (let* ((file (match args
1135 (expr (assoc-ref opts 'expression))
1136 (system (assoc-ref opts 'system))
1140 (G_ "both file and expression cannot be specified~%")))
1144 (load* file %user-module
1145 #:on-error (assoc-ref opts 'on-error)))
1147 (leave (G_ "no configuration specified~%")))))
1149 (dry? (assoc-ref opts 'dry-run?))
1150 (bootloader? (assoc-ref opts 'install-bootloader?))
1152 ((first second) second)
1156 (bootloader-configuration-target
1157 (operating-system-bootloader os)))))
1160 (set-build-options-from-command-line store opts)
1162 (run-with-store store
1163 (mbegin %store-monad
1164 (set-guile-for-build (default-guile))
1167 (export-extension-graph os (current-output-port)))
1169 (export-shepherd-graph os (current-output-port)))
1171 (unless (memq action '(build init))
1172 (warn-about-old-distro #:suggested-command
1173 "guix system reconfigure"))
1175 (perform-action action os
1177 #:derivations-only? (assoc-ref opts
1179 #:use-substitutes? (assoc-ref opts 'substitutes?)
1180 #:skip-safety-checks?
1181 (assoc-ref opts 'skip-safety-checks?)
1182 #:file-system-type (assoc-ref opts 'file-system-type)
1183 #:image-size (assoc-ref opts 'image-size)
1184 #:full-boot? (assoc-ref opts 'full-boot?)
1185 #:mappings (filter-map (match-lambda
1186 (('file-system-mapping . m)
1190 #:install-bootloader? bootloader?
1192 #:bootloader-target bootloader-target
1193 #:gc-root (assoc-ref opts 'gc-root)))))
1195 (warn-about-disk-space)))
1197 (define (resolve-subcommand name)
1198 (let ((module (resolve-interface
1199 `(guix scripts system ,(string->symbol name))))
1200 (proc (string->symbol (string-append "guix-system-" name))))
1201 (module-ref module proc)))
1203 (define (process-command command args opts)
1204 "Process COMMAND, one of the 'guix system' sub-commands. ARGS is its
1205 argument list and OPTS is the option alist."
1207 ;; The following commands do not need to use the store, and they do not need
1208 ;; an operating system configuration file.
1210 (let ((pattern (match args
1213 (x (leave (G_ "wrong number of arguments~%"))))))
1214 (list-generations pattern)))
1216 (apply (resolve-subcommand "search") args))
1217 ;; The following commands need to use the store, but they do not need an
1218 ;; operating system configuration file.
1219 ((delete-generations)
1220 (let ((pattern (match args
1223 (x (leave (G_ "wrong number of arguments~%"))))))
1225 (delete-matching-generations store %system-profile pattern)
1226 (reinstall-bootloader store (generation-number %system-profile)))))
1227 ((switch-generation)
1228 (let ((pattern (match args
1230 (x (leave (G_ "wrong number of arguments~%"))))))
1232 (set-build-options-from-command-line store opts)
1233 (switch-to-system-generation store pattern))))
1235 (let ((pattern (match args
1237 (x (leave (G_ "wrong number of arguments~%"))))))
1239 (set-build-options-from-command-line store opts)
1240 (roll-back-system store))))
1241 ;; The following commands need to use the store, and they also
1242 ;; need an operating system configuration file.
1243 (else (process-action command args opts))))
1245 (define (guix-system . args)
1246 (define (parse-sub-command arg result)
1247 ;; Parse sub-command ARG and augment RESULT accordingly.
1248 (if (assoc-ref result 'action)
1249 (alist-cons 'argument arg result)
1250 (let ((action (string->symbol arg)))
1252 ((build container vm vm-image disk-image reconfigure init
1253 extension-graph shepherd-graph
1254 list-generations delete-generations roll-back
1255 switch-generation search docker-image)
1256 (alist-cons 'action action result))
1257 (else (leave (G_ "~a: unknown action~%") action))))))
1259 (define (match-pair car)
1260 ;; Return a procedure that matches a pair with CAR.
1263 (and (eq? car head) tail))
1266 (define (option-arguments opts)
1267 ;; Extract the plain arguments from OPTS.
1268 (let* ((args (reverse (filter-map (match-pair 'argument) opts)))
1269 (count (length args))
1270 (action (assoc-ref opts 'action))
1271 (expr (assoc-ref opts 'expression)))
1273 (leave (G_ "wrong number of arguments for action '~a'~%")
1277 (format (current-error-port)
1278 (G_ "guix system: missing command name~%"))
1279 (format (current-error-port)
1280 (G_ "Try 'guix system --help' for more information.~%"))
1284 ((build container vm vm-image disk-image docker-image reconfigure)
1285 (unless (or (= count 1)
1286 (and expr (= count 0)))
1293 (with-error-handling
1294 (let* ((opts (parse-command-line args %options
1295 (list %default-options)
1298 (args (option-arguments opts))
1299 (command (assoc-ref opts 'action)))
1300 (parameterize ((%graft? (assoc-ref opts 'graft?)))
1301 (with-status-verbosity (or (assoc-ref opts 'verbosity)
1302 (if (eq? command 'build) 2 1))
1303 (process-command command args opts))))))
1305 ;;; Local Variables:
1306 ;;; eval: (put 'call-with-service-upgrade-info 'scheme-indent-function 1)
1309 ;;; system.scm ends here