diff --git a/doc/guix.texi b/doc/guix.texi index 6acde6621b..21082aece4 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -8272,6 +8272,50 @@ this: @end example @end defvr +@defvr {Scheme Variable} special-files-service-type +This is the service that sets up ``special files'' such as +@file{/bin/sh}; an instance of it is part of @code{%base-services}. + +The value associated with @code{special-files-service-type} services +must be a list of tuples where the first element is the ``special file'' +and the second element is its target. By default it is: + +@cindex @file{/bin/sh} +@cindex @file{sh}, in @file{/bin} +@example +`(("/bin/sh" ,(file-append @var{bash} "/bin/sh"))) +@end example + +@cindex @file{/usr/bin/env} +@cindex @file{env}, in @file{/usr/bin} +If you want to add, say, @code{/usr/bin/env} to your system, you can +change it to: + +@example +`(("/bin/sh" ,(file-append @var{bash} "/bin/sh")) + ("/usr/bin/env" ,(file-append @var{coreutils} "/bin/env"))) +@end example + +Since this is part of @code{%base-services}, you can use +@code{modify-services} to customize the set of special files +(@pxref{Service Reference, @code{modify-services}}). But the simple way +to add a special file is @i{via} the @code{extra-special-file} procedure +(see below.) +@end defvr + +@deffn {Scheme Procedure} extra-special-file @var{file} @var{target} +Use @var{target} as the ``special file'' @var{file}. + +For example, adding the following lines to the @code{services} field of +your operating system declaration leads to a @file{/usr/bin/env} +symlink: + +@example +(extra-special-file "/usr/bin/env" + (file-append coreutils "/bin/env")) +@end example +@end deffn + @deffn {Scheme Procedure} host-name-service @var{name} Return a service that sets the host name to @var{name}. @end deffn diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index e58304e83b..c4ed40e0de 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -28,7 +28,7 @@ (define-module (gnu build activation) activate-user-home activate-etc activate-setuid-programs - activate-/bin/sh + activate-special-files activate-modprobe activate-firmware activate-ptrace-attach @@ -383,10 +383,23 @@ (define (make-setuid-program prog) (for-each make-setuid-program programs)) -(define (activate-/bin/sh shell) - "Change /bin/sh to point to SHELL." - (symlink shell "/bin/sh.new") - (rename-file "/bin/sh.new" "/bin/sh")) +(define (activate-special-files special-files) + "Install the files listed in SPECIAL-FILES. Each element of SPECIAL-FILES +is a pair where the first element is the name of the special file and the +second element is the name it should appear at, such as: + + ((\"/bin/sh\" \"/gnu/store/…-bash/bin/sh\") + (\"/usr/bin/env\" \"/gnu/store/…-coreutils/bin/env\")) +" + (define install-special-file + (match-lambda + ((target file) + (let ((pivot (string-append target ".new"))) + (mkdir-p (dirname target)) + (symlink file pivot) + (rename-file pivot target))))) + + (for-each install-special-file special-files)) (define (activate-modprobe modprobe) "Tell the kernel to use MODPROBE to load modules." diff --git a/gnu/services.scm b/gnu/services.scm index e645889d30..6ac4f1322d 100644 --- a/gnu/services.scm +++ b/gnu/services.scm @@ -72,6 +72,8 @@ (define-module (gnu services) activation-service-type activation-service->script %linux-bare-metal-service + special-files-service-type + extra-special-file etc-service-type etc-directory setuid-program-service-type @@ -336,10 +338,6 @@ (define (service-activations) #~(begin (use-modules (gnu build activation)) - ;; Make sure /bin/sh is valid and current. - (activate-/bin/sh - (string-append #$(canonical-package bash) "/bin/sh")) - ;; Make sure the user accounting database exists. If it ;; does not exist, 'setutxent' does not create it and ;; thus there is no accounting at all. @@ -413,6 +411,25 @@ (define %linux-bare-metal-service ;; necessary or impossible in a container. (service linux-bare-metal-service-type #f)) +(define special-files-service-type + ;; Service to install "special files" such as /bin/sh and /usr/bin/env. + (service-type + (name 'special-files) + (extensions + (list (service-extension activation-service-type + (lambda (files) + #~(activate-special-files '#$files))))) + (compose concatenate) + (extend append))) + +(define (extra-special-file file target) + "Use TARGET as the \"special file\" FILE. For example, TARGET might be + (file-append coreutils \"/bin/env\") +and FILE could be \"/usr/bin/env\"." + (simple-service (string->symbol (string-append "special-file-" file)) + special-files-service-type + `((,file ,target)))) + (define (etc-directory service) "Return the directory for SERVICE, a service of type ETC-SERVICE-TYPE." (files->etc-directory (service-parameters service))) diff --git a/gnu/services/base.scm b/gnu/services/base.scm index d9f3a1445e..57601eab85 100644 --- a/gnu/services/base.scm +++ b/gnu/services/base.scm @@ -36,6 +36,7 @@ (define-module (gnu services base) #:select (alsa-utils crda eudev e2fsprogs fuse gpm kbd lvm2 rng-tools)) #:use-module ((gnu packages base) #:select (canonical-package glibc)) + #:use-module (gnu packages bash) #:use-module (gnu packages package-management) #:use-module (gnu packages lsof) #:use-module (gnu packages terminals) @@ -1558,6 +1559,10 @@ (define %base-services ;; The LVM2 rules are needed as soon as LVM2 or the device-mapper is ;; used, so enable them by default. The FUSE and ALSA rules are ;; less critical, but handy. - (udev-service #:rules (list lvm2 fuse alsa-utils crda)))) + (udev-service #:rules (list lvm2 fuse alsa-utils crda)) + + (service special-files-service-type + `(("/bin/sh" ,(file-append (canonical-package bash) + "/bin/sh")))))) ;;; base.scm ends here diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 8a6a7a1568..000a4ddecb 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -77,6 +77,11 @@ (define* (run-basic-test os command #:optional (name "basic") passed a gexp denoting the marionette, and it must return gexp that is inserted before the first test. This is used to introduce an extra initialization step, such as entering a LUKS passphrase." + (define special-files + (service-parameters + (fold-services (operating-system-services os) + #:target-type special-files-service-type))) + (define test (with-imported-modules '((gnu build marionette) (guix build syscalls)) @@ -120,6 +125,18 @@ (define marionette info --version") marionette))) + (test-equal "special files" + '#$special-files + (marionette-eval + '(begin + (use-modules (ice-9 match)) + + (map (match-lambda + ((file target) + (list file (readlink file)))) + '#$special-files)) + marionette)) + (test-assert "accounts" (let ((users (marionette-eval '(begin (use-modules (ice-9 match))