diff --git a/docs/plan.md b/docs/plan.md index 9d6c7a6..3d12740 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -298,6 +298,9 @@ Current progress: - rootfs population helpers now run through the jailed helper path too - image/installer/ISO assembly now records staged jail metadata and uses a dedicated assembly privileged policy surface +- install-time storage layout application is now executed as a rendered + privileged helper script under that policy instead of many scattered host-side + privileged calls - network is disabled by default in these jailed paths - union assembly mounts are now much smaller and omit host `/etc` and `devfs` - direct block-device `system install` is now an explicit opt-in under the diff --git a/modules/fruix/system/freebsd/media.scm b/modules/fruix/system/freebsd/media.scm index 68df84f..a2433c5 100644 --- a/modules/fruix/system/freebsd/media.scm +++ b/modules/fruix/system/freebsd/media.scm @@ -1507,10 +1507,12 @@ (assembly-privileged-policy-path (string-append staging-metadata-relative-root "/assembly-privileged-policy.scm")) (rootfs-populate-metadata-path (string-append staging-metadata-relative-root "/rootfs-populate.scm")) + (storage-apply-metadata-path (string-append staging-metadata-relative-root "/storage-apply.scm")) (rootfs-copy-metadata-path (string-append staging-metadata-relative-root "/rootfs-copy.scm")) (store-copy-metadata-path (string-append staging-metadata-relative-root "/store-copy.scm")) (assembly-privileged-policy-file (string-append rootfs assembly-privileged-policy-path)) (rootfs-populate-metadata-file (string-append rootfs rootfs-populate-metadata-path)) + (storage-apply-metadata-temp-file (string-append build-root "/storage-apply.scm")) (rootfs-copy-metadata-temp-file (string-append build-root "/rootfs-copy.scm")) (store-copy-metadata-temp-file (string-append build-root "/store-copy.scm")) (target-device #f) @@ -1549,8 +1551,12 @@ (set! storage-plan (assoc-ref (apply-freebsd-storage-layout effective-storage-layout #:root-mount-point mnt-root - #:privileged-policy privileged-policy) + #:privileged-policy privileged-policy + #:metadata-file storage-apply-metadata-temp-file) 'plan)) + (install-metadata-file-into-mounted-root privileged-policy + storage-apply-metadata-temp-file + (string-append mnt-root storage-apply-metadata-path)) (set! mounted-targets (freebsd-storage-plan-mount-targets storage-plan)) (let ((esp-entry (freebsd-storage-plan-partition-by-role storage-plan 'efi)) (root-entry (or (freebsd-storage-plan-partition-by-role storage-plan 'root) @@ -1604,6 +1610,7 @@ (install-metadata-path . ,install-metadata-relative-path) (assembly-privileged-policy-path . ,assembly-privileged-policy-path) (rootfs-populate-metadata-path . ,rootfs-populate-metadata-path) + (storage-apply-metadata-path . ,storage-apply-metadata-path) (rootfs-copy-metadata-path . ,rootfs-copy-metadata-path) (store-copy-metadata-path . ,store-copy-metadata-path) (closure-path . ,closure-path) @@ -1618,22 +1625,32 @@ (store-layout-file . ,(assoc-ref closure 'store-layout-file)) (store-items . ,store-items))) (lambda () - (for-each (lambda (mount-target) - (run-assembly-privileged-shell-command - privileged-policy - 'unmount-file-system - (string-append "umount " - (shell-quote mount-target) - " >/dev/null 2>&1 || true"))) - mounted-targets) - (when target-md - (run-assembly-privileged-shell-command + (when (or (pair? mounted-targets) target-md) + (run-assembly-privileged-script privileged-policy - 'mdconfig-detach - (string-append "mdconfig -d -u " - (shell-quote (string-drop target-md 2)) - " >/dev/null 2>&1 || true")) - (set! target-md #f)) + "fruix-install-cleanup" + (string-append + "#!/bin/sh\n" + "set +e\n" + (string-concatenate + (map (lambda (mount-target) + (string-append "umount " + (shell-quote mount-target) + " >/dev/null 2>&1 || true\n")) + mounted-targets)) + (if target-md + (string-append "mdconfig -d -u " + (shell-quote (string-drop target-md 2)) + " >/dev/null 2>&1 || true\n") + "")) + #:operations (delete-duplicates + (append (if (pair? mounted-targets) + '(unmount-file-system) + '()) + (if target-md + '(mdconfig-detach) + '()))))) + (set! target-md #f) (when (file-exists? build-root) (delete-file-recursively build-root)))))) diff --git a/modules/fruix/system/freebsd/storage.scm b/modules/fruix/system/freebsd/storage.scm index 3163aff..33e46db 100644 --- a/modules/fruix/system/freebsd/storage.scm +++ b/modules/fruix/system/freebsd/storage.scm @@ -324,6 +324,12 @@ (mount-targets . ,(freebsd-storage-plan-mount-targets plan)) (partitions . ,(action-ref plan 'partitions '())))) +(define (storage-shell-quote text) + (string-append "'" (string-replace-all text "'" "'\"'\"'") "'")) + +(define (render-shell-command argv) + (string-join (map storage-shell-quote argv) " ")) + (define (render-add-partition-action entry) (let* ((argv (append (list "gpart" "add" "-a" "1m") (let ((size (action-ref entry 'size #f))) @@ -333,7 +339,7 @@ (list "-t" (action-ref entry 'gpart-type #f) "-l" (action-ref entry 'partition-label #f) (action-ref entry 'device #f))))) - (string-join argv " "))) + (render-shell-command argv))) (define (render-freebsd-storage-layout-plan plan) (let ((actions (action-ref plan 'actions '()))) @@ -341,12 +347,15 @@ (map (lambda (entry) (case (action-ref entry 'kind #f) ((destroy-device) - (format #f "gpart destroy -F ~a >/dev/null 2>&1 || true" - (action-ref entry 'device #f))) + (string-append + (render-shell-command + (list "gpart" "destroy" "-F" (action-ref entry 'device #f))) + " >/dev/null 2>&1 || true")) ((create-partition-table) - (format #f "gpart create -s ~a ~a" - (symbol->string (action-ref entry 'partition-table #f)) - (action-ref entry 'device #f))) + (render-shell-command + (list "gpart" "create" "-s" + (symbol->string (action-ref entry 'partition-table #f)) + (action-ref entry 'device #f)))) ((add-partition) (render-add-partition-action entry)) ((format-file-system) @@ -355,89 +364,64 @@ (label (action-ref entry 'file-system-label #f))) (cond ((string=? format-name "msdosfs") - (format #f "newfs_msdos -L EFISYS ~a" partition-device)) + (render-shell-command + (list "newfs_msdos" "-L" "EFISYS" partition-device))) ((string=? format-name "ufs") - (format #f "newfs -U -L ~a ~a" label partition-device)) + (render-shell-command + (list "newfs" "-U" "-L" label partition-device))) (else (format #f "# unsupported filesystem format ~a on ~a" format-name partition-device))))) ((mkdir) - (format #f "mkdir -p ~a" (action-ref entry 'path #f))) + (render-shell-command + (list "mkdir" "-p" (action-ref entry 'path #f)))) ((mount-file-system) - (format #f "mount -t ~a ~a ~a" - (action-ref entry 'format #f) - (action-ref entry 'partition-device #f) - (action-ref entry 'mount-target #f))) + (render-shell-command + (list "mount" "-t" + (action-ref entry 'format #f) + (action-ref entry 'partition-device #f) + (action-ref entry 'mount-target #f)))) (else (format #f "# unknown storage action ~s" entry)))) actions) "\n"))) -(define (run-format-action entry privileged-policy) - (let ((format-name (action-ref entry 'format #f)) - (partition-device (action-ref entry 'partition-device #f)) - (label (action-ref entry 'file-system-label #f))) - (cond - ((string=? format-name "msdosfs") - (run-assembly-privileged-command privileged-policy - 'format-msdosfs - "newfs_msdos" "-L" "EFISYS" partition-device)) - ((string=? format-name "ufs") - (run-assembly-privileged-command privileged-policy - 'format-ufs - "newfs" "-U" "-L" label partition-device)) - (else - (error "unsupported filesystem format in FreeBSD storage backend" format-name entry))))) - -(define (run-action entry privileged-policy) +(define (storage-action->assembly-operations entry) (case (action-ref entry 'kind #f) - ((destroy-device) - (run-assembly-privileged-shell-command - privileged-policy - 'destroy-device - (string-append "gpart destroy -F " - (action-ref entry 'device #f) - " >/dev/null 2>&1 || true")) - #t) - ((create-partition-table) - (run-assembly-privileged-command privileged-policy - 'create-partition-table - "gpart" "create" "-s" - (symbol->string (action-ref entry 'partition-table #f)) - (action-ref entry 'device #f))) - ((add-partition) - (let* ((size (action-ref entry 'size #f)) - (argv (append (list privileged-policy - 'add-partition - "gpart" "add" "-a" "1m") - (if size - (list "-s" size) - '()) - (list "-t" (action-ref entry 'gpart-type #f) - "-l" (action-ref entry 'partition-label #f) - (action-ref entry 'device #f))))) - (apply run-assembly-privileged-command argv))) + ((destroy-device) '(destroy-device)) + ((create-partition-table) '(create-partition-table)) + ((add-partition) '(add-partition)) ((format-file-system) - (run-format-action entry privileged-policy)) - ((mkdir) - (run-assembly-privileged-command privileged-policy - 'create-mount-target - "mkdir" "-p" (action-ref entry 'path #f))) - ((mount-file-system) - (run-assembly-privileged-command privileged-policy - 'mount-file-system - "mount" "-t" - (action-ref entry 'format #f) - (action-ref entry 'partition-device #f) - (action-ref entry 'mount-target #f))) + (let ((format-name (action-ref entry 'format #f))) + (cond + ((string=? format-name "msdosfs") '(format-msdosfs)) + ((string=? format-name "ufs") '(format-ufs)) + (else + (error "unsupported filesystem format in FreeBSD storage backend" format-name entry))))) + ((mkdir) '(create-mount-target)) + ((mount-file-system) '(mount-file-system)) (else (error "unknown FreeBSD storage backend action" entry)))) +(define (storage-plan-assembly-operations plan) + (delete-duplicates + (append-map storage-action->assembly-operations + (action-ref plan 'actions '())))) + +(define (storage-plan-script plan) + (string-append "#!/bin/sh\n" + "set -eu\n" + (render-freebsd-storage-layout-plan plan) + "\n")) + (define* (apply-freebsd-storage-layout layout #:key (root-mount-point "/mnt") - (privileged-policy (default-assembly-privileged-policy))) + (privileged-policy (default-assembly-privileged-policy)) + metadata-file) (let ((plan (freebsd-storage-layout-plan layout #:root-mount-point root-mount-point))) - (for-each (lambda (entry) - (run-action entry privileged-policy)) - (action-ref plan 'actions '())) + (run-assembly-privileged-script privileged-policy + "fruix-storage-layout-apply" + (storage-plan-script plan) + #:operations (storage-plan-assembly-operations plan) + #:metadata-file metadata-file) `((plan . ,plan) (disk-device . ,(action-ref plan 'disk-device #f)) (root-mount-point . ,(action-ref plan 'root-mount-point #f)) diff --git a/modules/fruix/system/freebsd/utils.scm b/modules/fruix/system/freebsd/utils.scm index 35bbde4..c37489c 100644 --- a/modules/fruix/system/freebsd/utils.scm +++ b/modules/fruix/system/freebsd/utils.scm @@ -42,6 +42,7 @@ run-assembly-privileged-command run-assembly-privileged-shell-command assembly-privileged-command-output + run-assembly-privileged-script store-reference-closure copy-store-items-into-rootfs copy-rootfs-for-image @@ -404,6 +405,45 @@ " " (command->shell-fragment program args)))) +(define assembly-privileged-script-metadata-version "1") + +(define* (assembly-privileged-script-metadata policy name operations script) + `((assembly-privileged-script-metadata-version . ,assembly-privileged-script-metadata-version) + (name . ,name) + (policy . ,policy) + (operations . ,operations) + (script . ,script) + (command . ,(string-append (assembly-privileged-policy-command-prefix policy) + " sh