1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2014, 2015, 2016, 2017, 2018 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)
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 #:use-module (guix graph)
40 #:use-module (guix scripts graph)
41 #:use-module (guix build utils)
42 #:use-module (guix progress)
43 #:use-module ((guix build syscalls) #:select (terminal-columns))
44 #:use-module (gnu build install)
45 #:autoload (gnu build file-systems)
46 (find-partition-by-label find-partition-by-uuid)
47 #:autoload (gnu build linux-modules)
48 (device-module-aliases matching-modules)
49 #:use-module (gnu system linux-initrd)
50 #:use-module (gnu system)
51 #:use-module (gnu bootloader)
52 #:use-module (gnu system file-systems)
53 #:use-module (gnu system mapped-devices)
54 #:use-module (gnu system linux-container)
55 #:use-module (gnu system uuid)
56 #:use-module (gnu system vm)
57 #:use-module (gnu services)
58 #:use-module (gnu services shepherd)
59 #:use-module (gnu services herd)
60 #:use-module (srfi srfi-1)
61 #:use-module (srfi srfi-11)
62 #:use-module (srfi srfi-19)
63 #:use-module (srfi srfi-26)
64 #:use-module (srfi srfi-34)
65 #:use-module (srfi srfi-35)
66 #:use-module (srfi srfi-37)
67 #:use-module (ice-9 match)
68 #:use-module (rnrs bytevectors)
70 read-operating-system))
74 ;;; Operating system declaration.
78 ;; Module in which the machine description file is loaded.
79 (make-user-module '((gnu system)
81 (gnu system shadow))))
83 (define (read-operating-system file)
84 "Read the operating-system declaration from FILE and return it."
85 (load* file %user-module))
92 (define-syntax-rule (save-load-path-excursion body ...)
93 "Save the current values of '%load-path' and '%load-compiled-path', run
94 BODY..., and restore them."
95 (let ((path %load-path)
96 (cpath %load-compiled-path))
102 (set! %load-path path)
103 (set! %load-compiled-path cpath)))))
105 (define-syntax-rule (save-environment-excursion body ...)
106 "Save the current environment variables, run BODY..., and restore them."
107 (let ((env (environ)))
115 (define topologically-sorted*
116 (store-lift topologically-sorted))
119 (define* (copy-item item references target
120 #:key (log-port (current-error-port)))
121 "Copy ITEM to the store under root directory TARGET and register it with
122 REFERENCES as its set of references."
123 (let ((dest (string-append target item))
124 (state (string-append target "/var/guix")))
125 (format log-port "copying '~a'...~%" item)
127 ;; Remove DEST if it exists to make sure that (1) we do not fail badly
128 ;; while trying to overwrite it (see <http://bugs.gnu.org/20722>), and
129 ;; (2) we end up with the right contents.
130 (when (false-if-exception (lstat dest))
131 (for-each make-file-writable
132 (find-files dest (lambda (file stat)
133 (eq? 'directory (stat:type stat)))
135 (delete-file-recursively dest))
137 (copy-recursively item dest
138 #:log (%make-void-port "w"))
140 ;; Register ITEM; as a side-effect, it resets timestamps, etc.
141 ;; Explicitly use "TARGET/var/guix" as the state directory, to avoid
142 ;; reproducing the user's current settings; see
143 ;; <http://bugs.gnu.org/18049>.
144 (unless (register-path item
146 #:state-directory state
147 #:references references)
148 (leave (G_ "failed to register '~a' under '~a'~%")
151 (define* (copy-closure item target
152 #:key (log-port (current-error-port)))
153 "Copy ITEM and all its dependencies to the store under root directory
154 TARGET, and register them."
155 (mlet* %store-monad ((to-copy (topologically-sorted* (list item)))
156 (refs (mapm %store-monad references* to-copy))
157 (info (mapm %store-monad query-path-info*
159 (append to-copy (concatenate refs)))))
160 (size -> (reduce + 0 (map path-info-nar-size info))))
162 (progress-reporter/bar (length to-copy)
163 (format #f (G_ "copying to '~a'...")
166 (check-available-space size target)
168 (call-with-progress-reporter progress-bar
170 (let ((void (%make-void-port "w")))
171 (for-each (lambda (item refs)
172 (copy-item item refs target #:log-port void)
176 (return *unspecified*)))
178 (define* (install-bootloader installer-drv
182 "Call INSTALLER-DRV with error handling, in %STORE-MONAD."
183 (with-monad %store-monad
184 (let* ((gc-root (string-append target %gc-roots-directory
186 (temp-gc-root (string-append gc-root ".new"))
187 (install (and installer-drv
188 (derivation->output-path installer-drv)))
189 (bootcfg (derivation->output-path bootcfg)))
190 ;; Prepare the symlink to bootloader config file to make sure that it's
191 ;; a GC root when 'installer-drv' completes (being a bit paranoid.)
192 (switch-symlinks temp-gc-root bootcfg)
194 (unless (false-if-exception
196 (install-boot-config bootcfg bootcfg-file target)
198 (save-load-path-excursion (primitive-load install)))))
199 (delete-file temp-gc-root)
200 (leave (G_ "failed to install bootloader ~a~%") install))
202 ;; Register bootloader config file as a GC root so that its dependencies
203 ;; (background image, font, etc.) are not reclaimed.
204 (rename-file temp-gc-root gc-root)
207 (define* (install os-drv target
208 #:key (log-port (current-output-port))
209 bootloader-installer install-bootloader?
210 bootcfg bootcfg-file)
211 "Copy the closure of BOOTCFG, which includes the output of OS-DRV, to
212 directory TARGET. TARGET must be an absolute directory name since that's what
213 'register-path' expects.
215 When INSTALL-BOOTLOADER? is true, install bootloader using BOOTCFG."
216 (define (maybe-copy to-copy)
217 (with-monad %store-monad
218 (if (string=? target "/")
220 (warning (G_ "initializing the current root file system~%"))
223 ;; Make sure the target store exists.
224 (mkdir-p (string-append target (%store-prefix)))
226 ;; Copy items to the new store.
227 (copy-closure to-copy target #:log-port log-port)))))
229 ;; Make sure TARGET is root-owned when running as root, but still allow
230 ;; non-root uses (useful for testing.) See
231 ;; <http://lists.gnu.org/archive/html/guix-devel/2015-05/msg00452.html>.
232 (if (zero? (geteuid))
234 (warning (G_ "not running as 'root', so \
235 the ownership of '~a' may be incorrect!~%")
238 ;; If a previous installation was attempted, make sure we start anew; in
239 ;; particular, we don't want to keep a store database that might not
240 ;; correspond to what we're actually putting in the store.
241 (let ((state (string-append target "/var/guix")))
242 (when (file-exists? state)
243 (delete-file-recursively state)))
246 (let ((os-dir (derivation->output-path os-drv))
247 (format (lift format %store-monad))
248 (populate (lift2 populate-root-file-system %store-monad)))
251 ;; Copy the closure of BOOTCFG, which includes OS-DIR,
252 ;; eventual background image and so on.
254 (derivation->output-path bootcfg))
256 ;; Create a bunch of additional files.
257 (format log-port "populating '~a'...~%" target)
258 (populate os-dir target)
260 (mwhen install-bootloader?
261 (install-bootloader bootloader-installer
263 #:bootcfg-file bootcfg-file
271 (define %system-profile
272 ;; The system profile.
273 (string-append %state-directory "/profiles/system"))
275 (define-syntax-rule (with-shepherd-error-handling mbody ...)
276 "Catch and report Shepherd errors that arise when binding MBODY, a monadic
277 expression in %STORE-MONAD."
281 (guard (c ((shepherd-error? c)
282 (values (report-shepherd-error c) store)))
283 (values (run-with-store store (begin mbody ...))
285 (lambda (key proc format-string format-args errno . rest)
286 (warning (G_ "while talking to shepherd: ~a~%")
287 (apply format #f format-string format-args))
288 (values #f store)))))
290 (define (report-shepherd-error error)
291 "Report ERROR, a '&shepherd-error' error condition object."
292 (cond ((service-not-found-error? error)
293 (report-error (G_ "service '~a' could not be found~%")
294 (service-not-found-error-service error)))
295 ((action-not-found-error? error)
296 (report-error (G_ "service '~a' does not have an action '~a'~%")
297 (action-not-found-error-service error)
298 (action-not-found-error-action error)))
299 ((action-exception-error? error)
300 (report-error (G_ "exception caught while executing '~a' \
302 (action-exception-error-action error)
303 (action-exception-error-service error))
304 (print-exception (current-error-port) #f
305 (action-exception-error-key error)
306 (action-exception-error-arguments error)))
307 ((unknown-shepherd-error? error)
308 (report-error (G_ "something went wrong: ~s~%")
309 (unknown-shepherd-error-sexp error)))
310 ((shepherd-error? error)
311 (report-error (G_ "shepherd error~%")))
312 ((not error) ;not an error
315 (define (call-with-service-upgrade-info new-services mproc)
316 "Call MPROC, a monadic procedure in %STORE-MONAD, passing it the list of
317 names of services to load (upgrade), and the list of names of services to
319 (match (current-services)
321 (let-values (((to-unload to-restart)
322 (shepherd-service-upgrade services new-services)))
324 (map (compose first live-service-provision)
327 (with-monad %store-monad
328 (warning (G_ "failed to obtain list of shepherd services~%"))
331 (define (upgrade-shepherd-services os)
332 "Upgrade the Shepherd (PID 1) by unloading obsolete services and loading new
333 services specified in OS and not currently running.
335 This is currently very conservative in that it does not stop or unload any
336 running service. Unloading or stopping the wrong service ('udev', say) could
337 bring the system down."
340 (fold-services (operating-system-services os)
341 #:target-type shepherd-root-service-type)))
343 ;; Arrange to simply emit a warning if the service upgrade fails.
344 (with-shepherd-error-handling
345 (call-with-service-upgrade-info new-services
346 (lambda (to-restart to-unload)
347 (for-each (lambda (unload)
348 (info (G_ "unloading service '~a'...~%") unload)
349 (unload-service unload))
352 (with-monad %store-monad
353 (munless (null? new-services)
354 (let ((new-service-names (map shepherd-service-canonical-name new-services))
355 (to-restart-names (map shepherd-service-canonical-name to-restart))
356 (to-start (filter shepherd-service-auto-start? new-services)))
357 (info (G_ "loading new services:~{ ~a~}...~%") new-service-names)
358 (unless (null? to-restart-names)
359 ;; Listing TO-RESTART-NAMES in the message below wouldn't help
360 ;; because many essential services cannot be meaningfully
361 ;; restarted. See <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22039#30>.
362 (format #t (G_ "To complete the upgrade, run 'herd restart SERVICE' to stop,
363 upgrade, and restart each service that was not automatically restarted.\n")))
364 (mlet %store-monad ((files (mapm %store-monad
365 (compose lower-object
366 shepherd-service-file)
368 ;; Here we assume that FILES are exactly those that were computed
369 ;; as part of the derivation that built OS, which is normally the
371 (load-services/safe (map derivation->output-path files))
373 (for-each start-service
374 (map shepherd-service-canonical-name to-start))
377 (define* (switch-to-system os
378 #:optional (profile %system-profile))
379 "Make a new generation of PROFILE pointing to the directory of OS, switch to
380 it atomically, and then run OS's activation script."
381 (mlet* %store-monad ((drv (operating-system-derivation os))
382 (script (lower-object (operating-system-activation-script os))))
383 (let* ((system (derivation->output-path drv))
384 (number (+ 1 (generation-number profile)))
385 (generation (generation-file-name profile number)))
386 (switch-symlinks generation system)
387 (switch-symlinks profile generation)
389 (format #t (G_ "activating system...~%"))
391 ;; The activation script may change $PATH, among others, so protect
393 (save-environment-excursion
394 ;; Tell 'activate-current-system' what the new system is.
395 (setenv "GUIX_NEW_SYSTEM" system)
397 ;; The activation script may modify '%load-path' & co., so protect
398 ;; against that. This is necessary to ensure that
399 ;; 'upgrade-shepherd-services' gets to see the right modules when it
400 ;; computes derivations with 'gexp->derivation'.
401 (save-load-path-excursion
402 (primitive-load (derivation->output-path script))))
404 ;; Finally, try to update system services.
405 (upgrade-shepherd-services os))))
407 (define-syntax-rule (unless-file-not-found exp)
412 (if (= ENOENT (system-error-errno args))
414 (apply throw args)))))
416 (define (seconds->string seconds)
417 "Return a string representing the date for SECONDS."
418 (let ((time (make-time time-utc 0 seconds)))
419 (date->string (time-utc->date time)
422 (define* (profile-boot-parameters #:optional (profile %system-profile)
424 (reverse (generation-numbers profile))))
425 "Return a list of 'boot-parameters' for the generations of PROFILE specified
426 by NUMBERS, which is a list of generation numbers. The list is ordered from
427 the most recent to the oldest profiles."
428 (define (system->boot-parameters system number time)
429 (unless-file-not-found
430 (let* ((params (read-boot-parameters-file system))
431 (label (boot-parameters-label params)))
434 (label (string-append label " (#"
435 (number->string number) ", "
436 (seconds->string time) ")"))))))
437 (let* ((systems (map (cut generation-file-name profile <>)
439 (times (map (lambda (system)
440 (unless-file-not-found
441 (stat:mtime (lstat system))))
443 (filter-map system->boot-parameters systems numbers times)))
449 (define (roll-back-system store)
450 "Roll back the system profile to its previous generation. STORE is an open
451 connection to the store."
452 (switch-to-system-generation store "-1"))
456 ;;; Switch generations.
458 (define (switch-to-system-generation store spec)
459 "Switch the system profile to the generation specified by SPEC, and
460 re-install bootloader with a configuration file that uses the specified system
461 generation as its default entry. STORE is an open connection to the store."
462 (let ((number (relative-generation-spec->number %system-profile spec)))
465 (reinstall-bootloader store number)
466 (switch-to-generation* %system-profile number))
467 (leave (G_ "cannot switch to system generation '~a'~%") spec))))
469 (define* (system-bootloader-name #:optional (system %system-profile))
470 "Return the bootloader name stored in SYSTEM's \"parameters\" file."
471 (let ((params (unless-file-not-found
472 (read-boot-parameters-file system))))
473 (boot-parameters-bootloader-name params)))
475 (define (reinstall-bootloader store number)
476 "Re-install bootloader for existing system profile generation NUMBER.
477 STORE is an open connection to the store."
478 (let* ((generation (generation-file-name %system-profile number))
479 ;; Detect the bootloader used in %system-profile.
480 (bootloader (lookup-bootloader-by-name (system-bootloader-name)))
482 ;; Use the detected bootloader with default configuration.
483 ;; It will be enough to allow the system to boot.
484 (bootloader-config (bootloader-configuration
485 (bootloader bootloader)))
487 ;; Make the specified system generation the default entry.
488 (params (profile-boot-parameters %system-profile (list number)))
489 (old-generations (delv number (generation-numbers %system-profile)))
490 (old-params (profile-boot-parameters
491 %system-profile old-generations))
492 (entries (map boot-parameters->menu-entry params))
493 (old-entries (map boot-parameters->menu-entry old-params)))
494 (run-with-store store
496 ((bootcfg ((bootloader-configuration-file-generator bootloader)
497 bootloader-config entries
498 #:old-entries old-entries))
499 (bootcfg-file -> (bootloader-configuration-file bootloader))
501 (drvs -> (list bootcfg)))
503 (show-what-to-build* drvs)
504 (built-derivations drvs)
505 ;; Only install bootloader configuration file. Thus, no installer is
507 (install-bootloader #f
509 #:bootcfg-file bootcfg-file
510 #:target target))))))
517 (define (service-node-label service)
518 "Return a label to represent SERVICE."
519 (let ((type (service-kind service))
520 (value (service-value service)))
521 (string-append (symbol->string (service-type-name type))
522 (cond ((or (number? value) (symbol? value))
523 (string-append " " (object->string value)))
525 (string-append " " value))
526 ((file-system? value)
527 (string-append " " (file-system-mount-point value)))
531 (define (service-node-type services)
532 "Return a node type for SERVICES. Since <service> instances are not
533 self-contained (they express dependencies on service types, not on services),
534 we have to create the 'edges' procedure dynamically as a function of the full
538 (description "the DAG of services")
539 (identifier (lift1 object-address %store-monad))
540 (label service-node-label)
541 (edges (lift1 (service-back-edges services) %store-monad))))
543 (define (shepherd-service-node-label service)
544 "Return a label for a node representing a <shepherd-service>."
545 (string-join (map symbol->string (shepherd-service-provision service))))
547 (define (shepherd-service-node-type services)
548 "Return a node type for SERVICES, a list of <shepherd-service>."
550 (name "shepherd-service")
551 (description "the dependency graph of shepherd services")
552 (identifier (lift1 shepherd-service-node-label %store-monad))
553 (label shepherd-service-node-label)
554 (edges (lift1 (shepherd-service-back-edges services) %store-monad))))
561 (define* (display-system-generation number
562 #:optional (profile %system-profile))
563 "Display a summary of system generation NUMBER in a human-readable format."
564 (unless (zero? number)
565 (let* ((generation (generation-file-name profile number))
566 (params (read-boot-parameters-file generation))
567 (label (boot-parameters-label params))
568 (bootloader-name (boot-parameters-bootloader-name params))
569 (root (boot-parameters-root-device params))
570 (root-device (if (bytevector? root)
573 (kernel (boot-parameters-kernel params)))
574 (display-generation profile number)
575 (format #t (G_ " file name: ~a~%") generation)
576 (format #t (G_ " canonical file name: ~a~%") (readlink* generation))
577 ;; TRANSLATORS: Please preserve the two-space indentation.
578 (format #t (G_ " label: ~a~%") label)
579 (format #t (G_ " bootloader: ~a~%") bootloader-name)
581 ;; TRANSLATORS: The '~[', '~;', and '~]' sequences in this string must
582 ;; be preserved. They denote conditionals, such that the result will
584 ;; root device: UUID: 12345-678
586 ;; root device: label: "my-root"
588 ;; root device: /dev/sda3
589 (format #t (G_ " root device: ~[UUID: ~a~;label: ~s~;~a~]~%")
590 (cond ((uuid? root-device) 0)
591 ((file-system-label? root-device) 1)
593 (cond ((uuid? root-device)
594 (uuid->string root-device))
595 ((file-system-label? root-device)
596 (file-system-label->string root-device))
600 (format #t (G_ " kernel: ~a~%") kernel))))
602 (define* (list-generations pattern #:optional (profile %system-profile))
603 "Display in a human-readable format all the system generations matching
604 PATTERN, a string. When PATTERN is #f, display all the system generations."
605 (cond ((not (file-exists? profile)) ; XXX: race condition
606 (raise (condition (&profile-not-found-error
607 (profile profile)))))
608 ((string-null? pattern)
609 (for-each display-system-generation (profile-generations profile)))
610 ((matching-generations pattern profile)
613 (if (null-list? numbers)
616 (for-each display-system-generation numbers)))))
618 (leave (G_ "invalid syntax: ~a~%") pattern))))
622 ;;; File system declaration checks.
625 (define (check-file-system-availability file-systems)
626 "Check whether the UUIDs or partition labels that FILE-SYSTEMS refer to, if
627 any, are available. Raise an error if they're not."
630 (and (file-system-mount? fs)
631 (not (member (file-system-type fs)
632 %pseudo-file-system-types))
633 (not (memq 'bind-mount (file-system-flags fs)))))
638 (file-system-label? (file-system-device fs)))
643 (string? (file-system-device fs)))
648 (uuid? (file-system-device fs)))
653 (define (file-system-location* fs)
655 (source-properties->location
656 (file-system-location fs))))
658 (let-syntax ((error (syntax-rules ()
662 (format (current-error-port)
664 (for-each (lambda (fs)
667 (stat (file-system-device fs)))
669 (let ((errno (system-error-errno args))
670 (device (file-system-device fs)))
671 (error (G_ "~a: error: device '~a' not found: ~a~%")
672 (file-system-location* fs) device
674 (unless (string-prefix? "/" device)
675 (display-hint (format #f (G_ "If '~a' is a file system
676 label, write @code{(file-system-label ~s)} in your @code{device} field.")
679 (for-each (lambda (fs)
680 (let ((label (file-system-label->string
681 (file-system-device fs))))
682 (unless (find-partition-by-label label)
683 (error (G_ "~a: error: file system with label '~a' not found~%")
684 (file-system-location* fs) label))))
686 (for-each (lambda (fs)
687 (unless (find-partition-by-uuid (file-system-device fs))
688 (error (G_ "~a: error: file system with UUID '~a' not found~%")
689 (file-system-location* fs)
690 (uuid->string (file-system-device fs)))))
694 ;; Better be safe than sorry.
697 (define (check-mapped-devices os)
698 "Check that each of MAPPED-DEVICES is valid according to the 'check'
699 procedure of its type."
700 (define boot-mapped-devices
701 (operating-system-boot-mapped-devices os))
703 (define (needed-for-boot? md)
704 (memq md boot-mapped-devices))
706 (define initrd-modules
707 (operating-system-initrd-modules os))
709 (for-each (lambda (md)
710 (let ((check (mapped-device-kind-check
711 (mapped-device-type md))))
712 ;; We expect CHECK to raise an exception with a detailed
713 ;; '&message' if something goes wrong.
715 #:needed-for-boot? (needed-for-boot? md)
716 #:initrd-modules initrd-modules)))
717 (operating-system-mapped-devices os)))
719 (define (check-initrd-modules os)
720 "Check that modules needed by 'needed-for-boot' file systems in OS are
721 available in the initrd. Note that mapped devices are responsible for
722 checking this by themselves in their 'check' procedure."
723 (define (file-system-/dev fs)
724 (let ((device (file-system-device fs)))
729 (find-partition-by-uuid device))
730 ((? file-system-label?)
731 (find-partition-by-label (file-system-label->string device))))))
734 (filter file-system-needed-for-boot?
735 (operating-system-file-systems os)))
737 (for-each (lambda (fs)
738 (check-device-initrd-modules (file-system-/dev fs)
739 (operating-system-initrd-modules os)
740 (source-properties->location
741 (file-system-location fs))))
749 (define* (system-derivation-for-action os action
750 #:key image-size file-system-type
752 "Return as a monadic value the derivation for OS according to ACTION."
754 ((build init reconfigure)
755 (operating-system-derivation os))
757 (container-script os #:mappings mappings))
759 (system-qemu-image os #:disk-image-size image-size))
761 (system-qemu-image/shared-store-script os
762 #:full-boot? full-boot?
767 #:mappings mappings))
769 (system-disk-image os
770 #:name (match file-system-type
771 ("iso9660" "image.iso")
773 #:disk-image-size image-size
774 #:file-system-type file-system-type))
776 (system-docker-image os #:register-closures? #t))))
778 (define (maybe-suggest-running-guix-pull)
779 "Suggest running 'guix pull' if this has never been done before."
780 ;; The reason for this is that the 'guix' binding that we see here comes
781 ;; from either ~/.config/latest or, if it's missing, from the
782 ;; globally-installed Guix, which is necessarily older. See
783 ;; <http://lists.gnu.org/archive/html/guix-devel/2014-08/msg00057.html> for
786 (string-append (config-directory) "/current"))
788 (unless (file-exists? latest)
789 (warning (G_ "~a not found: 'guix pull' was never run~%") latest)
790 (warning (G_ "Consider running 'guix pull' before 'reconfigure'.~%"))
791 (warning (G_ "Failing to do that may downgrade your system!~%"))))
793 (define (bootloader-installer-derivation installer
794 bootloader device target)
795 "Return a file calling INSTALLER gexp with given BOOTLOADER, DEVICE
796 and TARGET arguments."
797 (with-monad %store-monad
798 (gexp->file "bootloader-installer"
799 (with-imported-modules '((gnu build bootloader)
802 (use-modules (gnu build bootloader)
804 (ice-9 binary-ports))
805 (#$installer #$bootloader #$device #$target))))))
807 (define* (perform-action action os
808 #:key skip-safety-checks?
810 dry-run? derivations-only?
811 use-substitutes? bootloader-target target
812 image-size file-system-type full-boot?
815 "Perform ACTION for OS. INSTALL-BOOTLOADER? specifies whether to install
816 bootloader; BOOTLOADER-TAGET is the target for the bootloader; TARGET is the
817 target root directory; IMAGE-SIZE is the size of the image to be built, for
818 the 'vm-image' and 'disk-image' actions. The root file system is created as a
819 FILE-SYSTEM-TYPE file system. FULL-BOOT? is used for the 'vm' action; it
820 determines whether to boot directly to the kernel or to the bootloader.
822 When DERIVATIONS-ONLY? is true, print the derivation file name(s) without
825 When GC-ROOT is a path, also make that path an indirect root of the build
826 output when building a system derivation, such as a disk image.
828 When SKIP-SAFETY-CHECKS? is true, skip the file system and initrd module
831 (cut format #t "~a~%" <>))
833 (when (eq? action 'reconfigure)
834 (maybe-suggest-running-guix-pull))
836 ;; Check whether the declared file systems exist. This is better than
837 ;; instantiating a broken configuration. Assume that we can only check if
839 (when (and (not skip-safety-checks?)
840 (memq action '(init reconfigure)))
841 (check-mapped-devices os)
842 (when (zero? (getuid))
843 (check-file-system-availability (operating-system-file-systems os))
844 (check-initrd-modules os)))
847 ((sys (system-derivation-for-action os action
848 #:file-system-type file-system-type
849 #:image-size image-size
850 #:full-boot? full-boot?
851 #:mappings mappings))
852 (bootloader -> (bootloader-configuration-bootloader
853 (operating-system-bootloader os)))
855 (let ((package (bootloader-package bootloader)))
857 (package->derivation package)
859 (bootcfg (if (eq? 'container action)
862 (operating-system-bootcfg
864 (if (eq? 'init action)
866 (map boot-parameters->menu-entry
867 (profile-boot-parameters)))))))
868 (bootcfg-file -> (bootloader-configuration-file bootloader))
869 (bootloader-installer
870 (let ((installer (bootloader-installer bootloader))
871 (target (or target "/")))
872 (bootloader-installer-derivation installer
874 bootloader-target target)))
876 ;; For 'init' and 'reconfigure', always build BOOTCFG, even if
877 ;; --no-bootloader is passed, because we then use it as a GC root.
878 ;; See <http://bugs.gnu.org/21068>.
879 (drvs -> (if (memq action '(init reconfigure))
880 (if (and install-bootloader? bootloader-package)
883 bootloader-installer)
886 (% (if derivations-only?
887 (return (for-each (compose println derivation-file-name)
889 (maybe-build drvs #:dry-run? dry-run?
890 #:use-substitutes? use-substitutes?))))
892 (if (or dry-run? derivations-only?)
895 (for-each (compose println derivation->output-path)
901 (switch-to-system os)
902 (mwhen install-bootloader?
903 (install-bootloader bootloader-installer
905 #:bootcfg-file bootcfg-file
909 (format #t (G_ "initializing operating system under '~a'...~%")
911 (install sys (canonicalize-path target)
912 #:install-bootloader? install-bootloader?
914 #:bootcfg-file bootcfg-file
915 #:bootloader-installer bootloader-installer))
917 ;; All we had to do was to build SYS and maybe register an
919 (let ((output (derivation->output-path sys)))
922 (register-root* (list output) gc-root))
923 (return output)))))))))
925 (define (export-extension-graph os port)
926 "Export the service extension graph of OS to PORT."
927 (let* ((services (operating-system-services os))
928 (system (find (lambda (service)
929 (eq? (service-kind service) system-service-type))
931 (export-graph (list system) (current-output-port)
932 #:node-type (service-node-type services)
933 #:reverse-edges? #t)))
935 (define (export-shepherd-graph os port)
936 "Export the graph of shepherd services of OS to PORT."
937 (let* ((services (operating-system-services os))
938 (pid1 (fold-services services
939 #:target-type shepherd-root-service-type))
940 (shepherds (service-value pid1)) ;list of <shepherd-service>
941 (sinks (filter (lambda (service)
942 (null? (shepherd-service-requirement service)))
944 (export-graph sinks (current-output-port)
945 #:node-type (shepherd-service-node-type shepherds)
946 #:reverse-edges? #t)))
954 (display (G_ "Usage: guix system [OPTION ...] ACTION [ARG ...] [FILE]
955 Build the operating system declared in FILE according to ACTION.
956 Some ACTIONS support additional ARGS.\n"))
958 (display (G_ "The valid values for ACTION are:\n"))
961 search search for existing service types\n"))
963 reconfigure switch to a new operating system configuration\n"))
965 roll-back switch to the previous operating system configuration\n"))
967 switch-generation switch to an existing operating system configuration\n"))
969 list-generations list the system generations\n"))
971 build build the operating system without installing anything\n"))
973 container build a container that shares the host's store\n"))
975 vm build a virtual machine image that shares the host's store\n"))
977 vm-image build a freestanding virtual machine image\n"))
979 disk-image build a disk image, suitable for a USB stick\n"))
981 docker-image build a Docker image\n"))
983 init initialize a root file system to run GNU\n"))
985 extension-graph emit the service extension graph in Dot format\n"))
987 shepherd-graph emit the graph of shepherd services in Dot format\n"))
989 (show-build-options-help)
991 -d, --derivation return the derivation of the given system"))
993 -e, --expression=EXPR consider the operating-system EXPR evaluates to
994 instead of reading FILE, when applicable"))
997 apply STRATEGY when an error occurs while reading FILE"))
999 --file-system-type=TYPE
1000 for 'disk-image', produce a root file system of TYPE
1001 (one of 'ext4', 'iso9660')"))
1003 --image-size=SIZE for 'vm-image', produce an image of SIZE"))
1005 --no-bootloader for 'init', do not install a bootloader"))
1007 --share=SPEC for 'vm', share host file system according to SPEC"))
1009 -r, --root=FILE for 'vm', 'vm-image', 'disk-image', 'container',
1010 and 'build', make FILE a symlink to the result, and
1011 register it as a garbage collector root"))
1013 --expose=SPEC for 'vm', expose host file system according to SPEC"))
1015 --full-boot for 'vm', make a full boot sequence"))
1017 --skip-checks skip file system and initrd module safety checks"))
1020 -h, --help display this help and exit"))
1022 -V, --version display version information and exit"))
1024 (show-bug-report-information))
1027 ;; Specifications of the command-line options.
1028 (cons* (option '(#\h "help") #f #f
1032 (option '(#\V "version") #f #f
1034 (show-version-and-exit "guix system")))
1035 (option '(#\e "expression") #t #f
1036 (lambda (opt name arg result)
1037 (alist-cons 'expression arg result)))
1038 (option '(#\d "derivation") #f #f
1039 (lambda (opt name arg result)
1040 (alist-cons 'derivations-only? #t result)))
1041 (option '("on-error") #t #f
1042 (lambda (opt name arg result)
1043 (alist-cons 'on-error (string->symbol arg)
1045 (option '(#\t "file-system-type") #t #f
1046 (lambda (opt name arg result)
1047 (alist-cons 'file-system-type arg
1049 (option '("image-size") #t #f
1050 (lambda (opt name arg result)
1051 (alist-cons 'image-size (size->number arg)
1053 (option '("no-bootloader" "no-grub") #f #f
1054 (lambda (opt name arg result)
1055 (alist-cons 'install-bootloader? #f result)))
1056 (option '("full-boot") #f #f
1057 (lambda (opt name arg result)
1058 (alist-cons 'full-boot? #t result)))
1059 (option '("skip-checks") #f #f
1060 (lambda (opt name arg result)
1061 (alist-cons 'skip-safety-checks? #t result)))
1063 (option '("share") #t #f
1064 (lambda (opt name arg result)
1065 (alist-cons 'file-system-mapping
1066 (specification->file-system-mapping arg #t)
1068 (option '("expose") #t #f
1069 (lambda (opt name arg result)
1070 (alist-cons 'file-system-mapping
1071 (specification->file-system-mapping arg #f)
1074 (option '(#\n "dry-run") #f #f
1075 (lambda (opt name arg result)
1076 (alist-cons 'dry-run? #t (alist-cons 'graft? #f result))))
1077 (option '(#\s "system") #t #f
1078 (lambda (opt name arg result)
1079 (alist-cons 'system arg
1080 (alist-delete 'system result eq?))))
1081 (option '(#\r "root") #t #f
1082 (lambda (opt name arg result)
1083 (alist-cons 'gc-root arg result)))
1084 %standard-build-options))
1086 (define %default-options
1087 ;; Alist of default option values.
1088 `((system . ,(%current-system))
1091 (print-build-trace? . #t)
1092 (print-extended-build-trace? . #t)
1093 (multiplexed-build-output? . #t)
1096 (file-system-type . "ext4")
1097 (image-size . guess)
1098 (install-bootloader? . #t)))
1105 (define (process-action action args opts)
1106 "Process ACTION, a sub-command, with the arguments are listed in ARGS.
1107 ACTION must be one of the sub-commands that takes an operating system
1108 declaration as an argument (a file name.) OPTS is the raw alist of options
1109 resulting from command-line parsing."
1110 (let* ((file (match args
1113 (expr (assoc-ref opts 'expression))
1114 (system (assoc-ref opts 'system))
1118 (G_ "both file and expression cannot be specified~%")))
1122 (load* file %user-module
1123 #:on-error (assoc-ref opts 'on-error)))
1125 (leave (G_ "no configuration specified~%")))))
1127 (dry? (assoc-ref opts 'dry-run?))
1128 (bootloader? (assoc-ref opts 'install-bootloader?))
1130 ((first second) second)
1134 (bootloader-configuration-target
1135 (operating-system-bootloader os)))))
1138 (set-build-options-from-command-line store opts)
1140 (run-with-store store
1141 (mbegin %store-monad
1142 (set-guile-for-build (default-guile))
1145 (export-extension-graph os (current-output-port)))
1147 (export-shepherd-graph os (current-output-port)))
1149 (unless (memq action '(build init))
1150 (warn-about-old-distro #:suggested-command
1151 "guix system reconfigure"))
1153 (perform-action action os
1155 #:derivations-only? (assoc-ref opts
1157 #:use-substitutes? (assoc-ref opts 'substitutes?)
1158 #:skip-safety-checks?
1159 (assoc-ref opts 'skip-safety-checks?)
1160 #:file-system-type (assoc-ref opts 'file-system-type)
1161 #:image-size (assoc-ref opts 'image-size)
1162 #:full-boot? (assoc-ref opts 'full-boot?)
1163 #:mappings (filter-map (match-lambda
1164 (('file-system-mapping . m)
1168 #:install-bootloader? bootloader?
1170 #:bootloader-target bootloader-target
1171 #:gc-root (assoc-ref opts 'gc-root)))))
1173 (warn-about-disk-space)))
1175 (define (resolve-subcommand name)
1176 (let ((module (resolve-interface
1177 `(guix scripts system ,(string->symbol name))))
1178 (proc (string->symbol (string-append "guix-system-" name))))
1179 (module-ref module proc)))
1181 (define (process-command command args opts)
1182 "Process COMMAND, one of the 'guix system' sub-commands. ARGS is its
1183 argument list and OPTS is the option alist."
1185 ;; The following commands do not need to use the store, and they do not need
1186 ;; an operating system configuration file.
1188 (let ((pattern (match args
1191 (x (leave (G_ "wrong number of arguments~%"))))))
1192 (list-generations pattern)))
1194 (apply (resolve-subcommand "search") args))
1195 ;; The following commands need to use the store, but they do not need an
1196 ;; operating system configuration file.
1197 ((switch-generation)
1198 (let ((pattern (match args
1200 (x (leave (G_ "wrong number of arguments~%"))))))
1202 (set-build-options-from-command-line store opts)
1203 (switch-to-system-generation store pattern))))
1205 (let ((pattern (match args
1207 (x (leave (G_ "wrong number of arguments~%"))))))
1209 (set-build-options-from-command-line store opts)
1210 (roll-back-system store))))
1211 ;; The following commands need to use the store, and they also
1212 ;; need an operating system configuration file.
1213 (else (process-action command args opts))))
1215 (define (guix-system . args)
1216 (define (parse-sub-command arg result)
1217 ;; Parse sub-command ARG and augment RESULT accordingly.
1218 (if (assoc-ref result 'action)
1219 (alist-cons 'argument arg result)
1220 (let ((action (string->symbol arg)))
1222 ((build container vm vm-image disk-image reconfigure init
1223 extension-graph shepherd-graph list-generations roll-back
1224 switch-generation search docker-image)
1225 (alist-cons 'action action result))
1226 (else (leave (G_ "~a: unknown action~%") action))))))
1228 (define (match-pair car)
1229 ;; Return a procedure that matches a pair with CAR.
1232 (and (eq? car head) tail))
1235 (define (option-arguments opts)
1236 ;; Extract the plain arguments from OPTS.
1237 (let* ((args (reverse (filter-map (match-pair 'argument) opts)))
1238 (count (length args))
1239 (action (assoc-ref opts 'action))
1240 (expr (assoc-ref opts 'expression)))
1242 (leave (G_ "wrong number of arguments for action '~a'~%")
1246 (format (current-error-port)
1247 (G_ "guix system: missing command name~%"))
1248 (format (current-error-port)
1249 (G_ "Try 'guix system --help' for more information.~%"))
1253 ((build container vm vm-image disk-image docker-image reconfigure)
1254 (unless (or (= count 1)
1255 (and expr (= count 0)))
1262 (with-error-handling
1263 (let* ((opts (parse-command-line args %options
1264 (list %default-options)
1267 (args (option-arguments opts))
1268 (command (assoc-ref opts 'action)))
1269 (parameterize ((%graft? (assoc-ref opts 'graft?)))
1270 (with-status-report (if (memq command '(init reconfigure))
1271 print-build-event/quiet
1273 (process-command command args opts))))))
1275 ;;; Local Variables:
1276 ;;; eval: (put 'call-with-service-upgrade-info 'scheme-indent-function 1)
1279 ;;; system.scm ends here