diff options
| author | Edouard Klein <edk@beaver-labs.com> | 2025-07-25 11:01:36 +0200 |
|---|---|---|
| committer | Maxim Cournoyer <maxim@guixotic.coop> | 2025-07-25 23:36:10 +0900 |
| commit | f05f8fb6b4e6982cd12db4c943deae95e5692924 (patch) | |
| tree | ac84ee77530f452cba26defac67a4d03c0ef42a5 /gnu/services/linux.scm | |
| parent | 8636c0910fa201f5f9f10cd10cfe8e98abf707a5 (diff) | |
services: Add vfs-mapping-service-type.
* gnu/services/linux.scm (vfs-mapping-service-type, vfs-mapping-configuration,
vfs-mapping-binding): New variables.
* doc/guix.texi: (Vfs Mapping Service): New subsubsection under "Linux Services".
Change-Id: I7ebd48afb809ded9fa6fe9eb80c618accb856716
Signed-off-by: Maxim Cournoyer <maxim@guixotic.coop>
Diffstat (limited to 'gnu/services/linux.scm')
| -rw-r--r-- | gnu/services/linux.scm | 164 |
1 files changed, 162 insertions, 2 deletions
diff --git a/gnu/services/linux.scm b/gnu/services/linux.scm index d7aee1b82e1..80c35717a92 100644 --- a/gnu/services/linux.scm +++ b/gnu/services/linux.scm | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | ;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz> | 7 | ;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz> |
| 8 | ;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu> | 8 | ;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu> |
| 9 | ;;; Copyright © 2023 Felix Lechner <felix.lechner@lease-up.com> | 9 | ;;; Copyright © 2023 Felix Lechner <felix.lechner@lease-up.com> |
| 10 | ;;; Copyright © 2025 Edouard Klein <edk@beaver-labs.com> | ||
| 10 | ;;; | 11 | ;;; |
| 11 | ;;; This file is part of GNU Guix. | 12 | ;;; This file is part of GNU Guix. |
| 12 | ;;; | 13 | ;;; |
| @@ -36,6 +37,7 @@ | |||
| 36 | #:use-module (gnu services configuration) | 37 | #:use-module (gnu services configuration) |
| 37 | #:use-module (gnu services shepherd) | 38 | #:use-module (gnu services shepherd) |
| 38 | #:use-module (gnu packages linux) | 39 | #:use-module (gnu packages linux) |
| 40 | #:use-module (gnu packages file-systems) | ||
| 39 | #:use-module (srfi srfi-1) | 41 | #:use-module (srfi srfi-1) |
| 40 | #:use-module (srfi srfi-26) | 42 | #:use-module (srfi srfi-26) |
| 41 | #:use-module (srfi srfi-34) | 43 | #:use-module (srfi srfi-34) |
| @@ -101,7 +103,11 @@ | |||
| 101 | zram-device-configuration-compression-algorithm | 103 | zram-device-configuration-compression-algorithm |
| 102 | zram-device-configuration-memory-limit | 104 | zram-device-configuration-memory-limit |
| 103 | zram-device-configuration-priority | 105 | zram-device-configuration-priority |
| 104 | zram-device-service-type)) | 106 | zram-device-service-type |
| 107 | |||
| 108 | vfs-mapping-service-type | ||
| 109 | vfs-mapping-configuration | ||
| 110 | vfs-mapping)) | ||
| 105 | 111 | ||
| 106 | 112 | ||
| 107 | ;;; | 113 | ;;; |
| @@ -547,7 +553,6 @@ the Linux @code{cachefiles} module.") | |||
| 547 | ;;; | 553 | ;;; |
| 548 | ;;; Zram device | 554 | ;;; Zram device |
| 549 | ;;; | 555 | ;;; |
| 550 | |||
| 551 | (define-record-type* <zram-device-configuration> | 556 | (define-record-type* <zram-device-configuration> |
| 552 | zram-device-configuration make-zram-device-configuration | 557 | zram-device-configuration make-zram-device-configuration |
| 553 | zram-device-configuration? | 558 | zram-device-configuration? |
| @@ -628,3 +633,158 @@ placed in a udev rules file." | |||
| 628 | (service-extension udev-service-type | 633 | (service-extension udev-service-type |
| 629 | (compose list zram-device-udev-rule)))) | 634 | (compose list zram-device-udev-rule)))) |
| 630 | (description "Creates a zram swap device."))) | 635 | (description "Creates a zram swap device."))) |
| 636 | |||
| 637 | |||
| 638 | ;;; | ||
| 639 | ;;; VFS Mapping. | ||
| 640 | ;;; | ||
| 641 | |||
| 642 | (define-record-type* <vfs-mapping> | ||
| 643 | vfs-mapping make-vfs-mapping | ||
| 644 | vfs-mapping? | ||
| 645 | (source vfs-mapping-source) | ||
| 646 | (destination vfs-mapping-destination) | ||
| 647 | (policy vfs-mapping-policy | ||
| 648 | (default 'translate)) | ||
| 649 | (user vfs-mapping-user | ||
| 650 | (default #f)) | ||
| 651 | (group vfs-mapping-group | ||
| 652 | (default "users")) | ||
| 653 | (name vfs-mapping-name | ||
| 654 | (default (string-append | ||
| 655 | (vfs-mapping-source this-record) "-[" | ||
| 656 | (vfs-mapping-policy this-record) "]->" | ||
| 657 | (vfs-mapping-destination this-record))) | ||
| 658 | (thunked)) | ||
| 659 | (requirement vfs-mapping-requirement | ||
| 660 | (default '(file-systems user-homes)))) | ||
| 661 | |||
| 662 | (define (vfs-mapping-policy? x) | ||
| 663 | (and (symbol? x) | ||
| 664 | (or (memq x '(bind translate overlay))))) | ||
| 665 | |||
| 666 | (define (path-like? x) | ||
| 667 | (or (string? x) | ||
| 668 | (file-like? x) | ||
| 669 | (gexp? x))) | ||
| 670 | |||
| 671 | (define (valid-vfs-mapping? x) | ||
| 672 | ;; User must be set iff we are going to use it | ||
| 673 | (and (vfs-mapping? x) | ||
| 674 | (path-like? (vfs-mapping-source x)) | ||
| 675 | (path-like? (vfs-mapping-destination x)) | ||
| 676 | (string? (vfs-mapping-name x)) | ||
| 677 | (vfs-mapping-policy? (vfs-mapping-policy x)) | ||
| 678 | (cond | ||
| 679 | ((eq? (vfs-mapping-policy x) 'bind) | ||
| 680 | (not (vfs-mapping-user x))) | ||
| 681 | (#t | ||
| 682 | (and (string? (vfs-mapping-user x)) | ||
| 683 | (string? (vfs-mapping-group x))))))) | ||
| 684 | |||
| 685 | (define list-of-vfs-mapping? (list-of valid-vfs-mapping?)) | ||
| 686 | |||
| 687 | (define-configuration/no-serialization vfs-mapping-configuration | ||
| 688 | (bindfs (gexp #~(string-append #$bindfs "/bin/bindfs")) | ||
| 689 | "The bindfs command to use.") | ||
| 690 | (fusermount (gexp #~(string-append #$fuse-2 "/bin/fusermount")) | ||
| 691 | "The fusermount command to use.") | ||
| 692 | (umount (gexp #~(string-append #$util-linux+udev "/bin/umount")) | ||
| 693 | "The umount command to use.") | ||
| 694 | (bindings (list-of-vfs-mapping '()) | ||
| 695 | "The list of bindings to mount")) | ||
| 696 | |||
| 697 | (define vfs-mapping-shepherd-services | ||
| 698 | (match-record-lambda <vfs-mapping-configuration> | ||
| 699 | (fusermount bindfs umount bindings) | ||
| 700 | (map | ||
| 701 | (match-record-lambda <vfs-mapping> | ||
| 702 | (source destination policy user group name requirement) | ||
| 703 | (shepherd-service | ||
| 704 | ;; Each binding has its own service | ||
| 705 | (provision (list (string->symbol name))) | ||
| 706 | ;; Make sure the homes are already present | ||
| 707 | (requirement requirement) | ||
| 708 | (stop | ||
| 709 | #~(lambda args | ||
| 710 | (match (quote #$policy) | ||
| 711 | ('bind (invoke #$umount #$destination)) | ||
| 712 | ('translate (invoke #$fusermount "-u" #$destination)) | ||
| 713 | ('overlay (begin | ||
| 714 | ;; First the bindfs | ||
| 715 | (invoke #$fusermount "-u" #$destination) | ||
| 716 | ;; then the overlay | ||
| 717 | (invoke #$umount #$destination)))) | ||
| 718 | #f)) | ||
| 719 | (start | ||
| 720 | #~(lambda args | ||
| 721 | (define (mkdir-recursively dir user group) | ||
| 722 | ;; Like mkdir-p, but chown all created directories to the | ||
| 723 | ;; specified user. | ||
| 724 | (unless (eq? dir "/") | ||
| 725 | (when (not (file-exists? dir)) | ||
| 726 | (mkdir-recursively (dirname dir) user group) | ||
| 727 | (mkdir dir) | ||
| 728 | (let* ((pw (getpw user)) | ||
| 729 | (uid (passwd:uid pw)) | ||
| 730 | (gid (passwd:gid pw))) | ||
| 731 | (chown dir uid gid))))) | ||
| 732 | (mkdir-recursively #$destination #$user #$group) | ||
| 733 | (let* ((stat (stat #$source)) | ||
| 734 | (uid (stat:uid stat)) | ||
| 735 | (gid (stat:gid stat)) | ||
| 736 | (source-user (passwd:name (getpwuid uid))) | ||
| 737 | (source-group (group:name (getgrgid gid)))) | ||
| 738 | (match (quote #$policy) | ||
| 739 | ('bind | ||
| 740 | (mount #$source #$destination | ||
| 741 | #f ;type | ||
| 742 | MS_BIND)) ;flags (bind mount) | ||
| 743 | ('translate | ||
| 744 | (invoke | ||
| 745 | #$bindfs | ||
| 746 | (string-append "--create-for-group=" source-group) | ||
| 747 | (string-append "--create-for-user=" source-user) | ||
| 748 | (string-append "--force-user=" #$user) | ||
| 749 | (string-append "--force-group=" #$group) | ||
| 750 | "-o" "nonempty" | ||
| 751 | #$source #$destination)) | ||
| 752 | ('overlay | ||
| 753 | (let ((overlay (string-append #$destination "-overlay")) | ||
| 754 | (workdir (string-append #$destination "-workdir"))) | ||
| 755 | (mkdir-recursively overlay #$user #$group) | ||
| 756 | (mkdir-recursively workdir #$user #$group) | ||
| 757 | (mount "overlay" ;source | ||
| 758 | #$destination | ||
| 759 | "overlay" ;type | ||
| 760 | 0 ;flags | ||
| 761 | (string-append ;options | ||
| 762 | "lowerdir=" #$source "," | ||
| 763 | "upperdir=" overlay "," | ||
| 764 | "workdir=" workdir)) | ||
| 765 | ;; Remount the target over itself to make it appear as if | ||
| 766 | ;; owned by user-name and user-group. | ||
| 767 | (invoke | ||
| 768 | #$bindfs | ||
| 769 | (string-append "--create-for-group=" source-group) | ||
| 770 | (string-append "--create-for-user=" source-user) | ||
| 771 | (string-append "--force-user=" #$user) | ||
| 772 | (string-append "--force-group=" #$group) | ||
| 773 | #$destination #$destination))))) | ||
| 774 | #t)))) | ||
| 775 | bindings))) | ||
| 776 | |||
| 777 | (define vfs-mapping-service-type | ||
| 778 | (service-type | ||
| 779 | (name 'vfs-mapping) | ||
| 780 | (extensions (list | ||
| 781 | (service-extension shepherd-root-service-type | ||
| 782 | vfs-mapping-shepherd-services))) | ||
| 783 | (compose concatenate) | ||
| 784 | (extend (lambda (original extensions) | ||
| 785 | (vfs-mapping-configuration | ||
| 786 | (inherit original) | ||
| 787 | (bindings (append (vfs-mapping-configuration-bindings original) | ||
| 788 | extensions))))) | ||
| 789 | (default-value (vfs-mapping-configuration)) | ||
| 790 | (description "Share or expose a file name under a different name."))) | ||
