From 26905ec8a61f2e641fec1517b045da1d89a41cf6 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 7 Jan 2017 21:09:15 +0100 Subject: file-systems: Refactor check-file-system. * gnu/build/file-systems.scm (check-file-system): Use file-system type specific checker. (check-ext2-file-system): New variable. --- gnu/build/file-systems.scm | 55 +++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 20 deletions(-) (limited to 'gnu/build') diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm index c121ca5f8b..d753b6b792 100644 --- a/gnu/build/file-systems.scm +++ b/gnu/build/file-systems.scm @@ -135,6 +135,14 @@ if DEVICE does not contain an ext2 file system." #f if SBLOCK has no volume name." (null-terminated-latin1->string (sub-bytevector sblock 120 16))) +(define (check-ext2-file-system device) + "Return the health of an ext2 file system on DEVICE." + (match (status:exit-val + (system* "e2fsck" "-v" "-p" "-C" "0" device)) + (0 'pass) + (1 'errors-corrected) + (2 'reboot-required) + (_ 'fatal-error))) ;;; @@ -400,26 +408,33 @@ the following: (define (check-file-system device type) "Run a file system check of TYPE on DEVICE." - (define fsck - (string-append "fsck." type)) - - (let ((status (system* fsck "-v" "-p" "-C" "0" device))) - (match (status:exit-val status) - (0 - #t) - (1 - (format (current-error-port) "'~a' corrected errors on ~a; continuing~%" - fsck device)) - (2 - (format (current-error-port) "'~a' corrected errors on ~a; rebooting~%" - fsck device) - (sleep 3) - (reboot)) - (code - (format (current-error-port) "'~a' exited with code ~a on ~a; \ -spawning Bourne-like REPL~%" - fsck code device) - (start-repl %bournish-language))))) + (define check-procedure + (cond + ((string-prefix? "ext" type) check-ext2-file-system) + (else #f))) + + (if check-procedure + (match (check-procedure device) + ('pass + #t) + ('errors-corrected + (format (current-error-port) + "File system check corrected errors on ~a; continuing~%" + device)) + ('reboot-required + (format (current-error-port) + "File system check corrected errors on ~a; rebooting~%" + device) + (sleep 3) + (reboot)) + ('fatal-error + (format (current-error-port) + "File system check on ~a failed; spawning Bourne-like REPL~%" + device) + (start-repl %bournish-language))) + (format (current-error-port) + "No file system check procedure for ~a; skipping~%" + device))) (define (mount-flags->bit-mask flags) "Return the number suitable for the 'flags' argument of 'mount' that -- cgit v1.2.3 From ab4e939c50b579eaee634c7c90c600f9c9f3aa3f Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 8 Jan 2017 00:03:50 +0100 Subject: file-systems: Refactor file-system predicates. * gnu/build/file-systems.scm (partition-field-reader, read-partition-field, %partition-label-readers, %partition-uuid-readers, read-partition-label, read-partition-uuid): New variables. (partition-predicate, partition-label-predicate, partition-uuid-predicate, luks-partition-uuid-predicate): Use partition field readers. (find-partition): New variable. (find-partition-by-label, find-partition-by-uuid, find-partition-by-luks-uuid): Use find-partition-by. --- gnu/build/file-systems.scm | 99 +++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 41 deletions(-) (limited to 'gnu/build') diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm index d753b6b792..e76854490c 100644 --- a/gnu/build/file-systems.scm +++ b/gnu/build/file-systems.scm @@ -1,6 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2014, 2015, 2016 Ludovic Courtès -;;; Copyright © 2016 David Craven +;;; Copyright © 2016, 2017 David Craven ;;; ;;; This file is part of GNU Guix. ;;; @@ -238,56 +238,73 @@ warning and #f as the result." (else (apply throw args)))))))) -(define (partition-predicate read field =) +(define (partition-field-reader read field) + "Return a procedure that takes a device and returns the value of a FIELD in +the partition superblock or #f." + (let ((read (ENOENT-safe read))) + (lambda (device) + (let ((sblock (read device))) + (and sblock + (field sblock)))))) + +(define (read-partition-field device partition-field-readers) + "Returns the value of a FIELD in the partition superblock of DEVICE or #f. It +takes a list of PARTITION-FIELD-READERS and returns the result of the first +partition field reader that returned a value." + (match (filter-map (cut apply <> (list device)) partition-field-readers) + ((field . _) field) + (_ #f))) + +(define %partition-label-readers + (list (partition-field-reader read-ext2-superblock + ext2-superblock-volume-name))) + +(define %partition-uuid-readers + (list (partition-field-reader read-ext2-superblock + ext2-superblock-uuid))) + +(define read-partition-label + (cut read-partition-field <> %partition-label-readers)) + +(define read-partition-uuid + (cut read-partition-field <> %partition-uuid-readers)) + +(define (partition-predicate reader =) "Return a predicate that returns true if the FIELD of partition header that was READ is = to the given value." - (let ((read (ENOENT-safe read))) - (lambda (expected) - "Return a procedure that, when applied to a partition name such as \"sda1\", -returns #t if that partition's volume name is LABEL." - (lambda (part) - (let* ((device (string-append "/dev/" part)) - (sblock (read device))) - (and sblock - (let ((actual (field sblock))) - (and actual - (= actual expected))))))))) + (lambda (expected) + (lambda (device) + (let ((actual (reader device))) + (and actual + (= actual expected)))))) (define partition-label-predicate - (partition-predicate read-ext2-superblock - ext2-superblock-volume-name - string=?)) + (partition-predicate read-partition-label string=?)) (define partition-uuid-predicate - (partition-predicate read-ext2-superblock - ext2-superblock-uuid - bytevector=?)) + (partition-predicate read-partition-uuid bytevector=?)) (define luks-partition-uuid-predicate - (partition-predicate read-luks-header - luks-header-uuid - bytevector=?)) + (partition-predicate + (partition-field-reader read-luks-header luks-header-uuid) + bytevector=?)) -(define (find-partition-by-label label) - "Return the first partition found whose volume name is LABEL, or #f if none +(define (find-partition predicate) + "Return the first partition found that matches PREDICATE, or #f if none were found." - (and=> (find (partition-label-predicate label) - (disk-partitions)) - (cut string-append "/dev/" <>))) - -(define (find-partition-by-uuid uuid) - "Return the first partition whose unique identifier is UUID (a bytevector), -or #f if none was found." - (and=> (find (partition-uuid-predicate uuid) - (disk-partitions)) - (cut string-append "/dev/" <>))) - -(define (find-partition-by-luks-uuid uuid) - "Return the first LUKS partition whose unique identifier is UUID (a bytevector), -or #f if none was found." - (and=> (find (luks-partition-uuid-predicate uuid) - (disk-partitions)) - (cut string-append "/dev/" <>))) + (lambda (expected) + (find (predicate expected) + (map (cut string-append "/dev/" <>) + (disk-partitions))))) + +(define find-partition-by-label + (find-partition partition-label-predicate)) + +(define find-partition-by-uuid + (find-partition partition-uuid-predicate)) + +(define find-partition-by-luks-uuid + (find-partition luks-partition-uuid-predicate)) ;;; -- cgit v1.2.3 From b1a505baf61cc771197eb44af9173f31d2bace46 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 30 Nov 2016 19:30:12 +0100 Subject: system: Add btrfs file system support. * gnu/build/file-systems.scm (%btrfs-endianness, btrfs-superblock?, read-btrfs-superblock, btrfs-superblock-uuid, btrfs-superblock-volume-name, check-btrfs-file-system): New variables. (%paritition-label-readers, %partition-uuid-readers): Add btrfs readers. * gnu/system/linux-initrd.scm (linux-modules): Add btrfs modules when a btrfs file-system is used. * gnu/tests/install.scm (%btrfs-root-os %btrfs-root-os-source, %btrfs-root-installation-script, %test-btrfs-root-os): New system test. * doc/guix.texi: Adjust accordingly. Fixes . --- doc/guix.texi | 6 ++-- gnu/build/file-systems.scm | 46 +++++++++++++++++++++++++-- gnu/system/linux-initrd.scm | 6 ++++ gnu/tests/install.scm | 77 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 129 insertions(+), 6 deletions(-) (limited to 'gnu/build') diff --git a/doc/guix.texi b/doc/guix.texi index d46a7743d0..086895996f 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6919,9 +6919,9 @@ cfdisk Once you are done partitioning the target hard disk drive, you have to create a file system on the relevant partition(s)@footnote{Currently -GuixSD pretty much assumes an ext4 file system. In particular, code -that reads partition UUIDs and labels only works with ext4. This will -be fixed in the future.}. +GuixSD only supports ext4 and btrfs file systems. In particular, code +that reads partition UUIDs and labels only works for these file system +types.}. Preferably, assign partitions a label so that you can easily and reliably refer to them in @code{file-system} declarations (@pxref{File diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm index e76854490c..6e5c6aaf15 100644 --- a/gnu/build/file-systems.scm +++ b/gnu/build/file-systems.scm @@ -144,6 +144,43 @@ if DEVICE does not contain an ext2 file system." (2 'reboot-required) (_ 'fatal-error))) + +;;; +;;; Btrfs file systems. +;;; + +;; . + +(define-syntax %btrfs-endianness + ;; Endianness of btrfs file systems. + (identifier-syntax (endianness little))) + +(define (btrfs-superblock? sblock) + "Return #t when SBLOCK is a btrfs superblock." + (bytevector=? (sub-bytevector sblock 64 8) + (string->utf8 "_BHRfS_M"))) + +(define (read-btrfs-superblock device) + "Return the raw contents of DEVICE's btrfs superblock as a bytevector, or #f +if DEVICE does not contain a btrfs file system." + (read-superblock device 65536 4096 btrfs-superblock?)) + +(define (btrfs-superblock-uuid sblock) + "Return the UUID of a btrfs superblock SBLOCK as a 16-byte bytevector." + (sub-bytevector sblock 32 16)) + +(define (btrfs-superblock-volume-name sblock) + "Return the volume name of SBLOCK as a string of at most 256 characters, or +#f if SBLOCK has no volume name." + (null-terminated-latin1->string (sub-bytevector sblock 299 256))) + +(define (check-btrfs-file-system device) + "Return the health of a btrfs file system on DEVICE." + (match (status:exit-val + (system* "btrfs" "device" "scan")) + (0 'pass) + (_ 'fatal-error))) + ;;; ;;; LUKS encrypted devices. @@ -257,11 +294,15 @@ partition field reader that returned a value." (define %partition-label-readers (list (partition-field-reader read-ext2-superblock - ext2-superblock-volume-name))) + ext2-superblock-volume-name) + (partition-field-reader read-btrfs-superblock + btrfs-superblock-volume-name))) (define %partition-uuid-readers (list (partition-field-reader read-ext2-superblock - ext2-superblock-uuid))) + ext2-superblock-uuid) + (partition-field-reader read-btrfs-superblock + btrfs-superblock-uuid))) (define read-partition-label (cut read-partition-field <> %partition-label-readers)) @@ -428,6 +469,7 @@ the following: (define check-procedure (cond ((string-prefix? "ext" type) check-ext2-file-system) + ((string-prefix? "btrfs" type) check-btrfs-file-system) (else #f))) (if check-procedure diff --git a/gnu/system/linux-initrd.scm b/gnu/system/linux-initrd.scm index a787072ba7..4a753cdadb 100644 --- a/gnu/system/linux-initrd.scm +++ b/gnu/system/linux-initrd.scm @@ -197,6 +197,9 @@ loaded at boot time in the order in which they appear." ,@(if (find (file-system-type-predicate "vfat") file-systems) '("nls_iso8859-1") '()) + ,@(if (find (file-system-type-predicate "btrfs") file-systems) + '("btrfs") + '()) ,@(if volatile-root? '("fuse") '()) @@ -214,6 +217,9 @@ loaded at boot time in the order in which they appear." file-systems) (list fatfsck/static) '()) + ,@(if (find (file-system-type-predicate "btrfs") file-systems) + (list btrfs-progs/static) + '()) ,@(if volatile-root? (list unionfs-fuse/static) '()))) diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm index 4779b80e94..ae54154c5c 100644 --- a/gnu/tests/install.scm +++ b/gnu/tests/install.scm @@ -36,7 +36,8 @@ #:export (%test-installed-os %test-separate-store-os %test-raid-root-os - %test-encrypted-os)) + %test-encrypted-os + %test-btrfs-root-os)) ;;; Commentary: ;;; @@ -518,4 +519,78 @@ build (current-guix) and then store a couple of full system images.") (run-basic-test %encrypted-root-os command "encrypted-root-os" #:initialization enter-luks-passphrase))))) + +;;; +;;; Btrfs root file system. +;;; + +(define-os-with-source (%btrfs-root-os %btrfs-root-os-source) + ;; The OS we want to install. + (use-modules (gnu) (gnu tests) (srfi srfi-1)) + + (operating-system + (host-name "liberigilo") + (timezone "Europe/Paris") + (locale "en_US.UTF-8") + + (bootloader (grub-configuration (device "/dev/vdb"))) + (kernel-arguments '("console=ttyS0")) + (file-systems (cons (file-system + (device "my-root") + (title 'label) + (mount-point "/") + (type "btrfs")) + %base-file-systems)) + (users (cons (user-account + (name "charlie") + (group "users") + (home-directory "/home/charlie") + (supplementary-groups '("wheel" "audio" "video"))) + %base-user-accounts)) + (services (cons (service marionette-service-type + (marionette-configuration + (imported-modules '((gnu services herd) + (guix combinators))))) + %base-services)))) + +(define %btrfs-root-installation-script + ;; Shell script of a simple installation. + "\ +. /etc/profile +set -e -x +guix --version + +export GUIX_BUILD_OPTIONS=--no-grafts +ls -l /run/current-system/gc-roots +parted --script /dev/vdb mklabel gpt \\ + mkpart primary ext2 1M 3M \\ + mkpart primary ext2 3M 1G \\ + set 1 boot on \\ + set 1 bios_grub on +mkfs.btrfs -L my-root /dev/vdb2 +mount /dev/vdb2 /mnt +btrfs subvolume create /mnt/home +herd start cow-store /mnt +mkdir /mnt/etc +cp /etc/target-config.scm /mnt/etc/config.scm +guix system build /mnt/etc/config.scm +guix system init /mnt/etc/config.scm /mnt --no-substitutes +sync +reboot\n") + +(define %test-btrfs-root-os + (system-test + (name "btrfs-root-os") + (description + "Test basic functionality of an OS installed like one would do by hand. +This test is expensive in terms of CPU and storage usage since we need to +build (current-guix) and then store a couple of full system images.") + (value + (mlet* %store-monad ((image (run-install %btrfs-root-os + %btrfs-root-os-source + #:script + %btrfs-root-installation-script)) + (command (qemu-command/writable-image image))) + (run-basic-test %btrfs-root-os command "btrfs-root-os"))))) + ;;; install.scm ends here -- cgit v1.2.3