aboutsummaryrefslogtreecommitdiff
path: root/gnu/build
diff options
context:
space:
mode:
authorMark H Weaver <mhw@netris.org>2014-09-11 18:26:28 -0400
committerMark H Weaver <mhw@netris.org>2014-09-11 18:26:28 -0400
commit66ea98e321e93b0806f6870d77dd4c00e7e720c0 (patch)
tree21778401485e3b8683bbc6a31769233c059683b1 /gnu/build
parentda5538ef44bfa74d3e435f9f557374eabba5dc1e (diff)
parent5dae0186dea1e72e73bf223161620cfeddef5a63 (diff)
downloadguix-66ea98e321e93b0806f6870d77dd4c00e7e720c0.tar.gz
guix-66ea98e321e93b0806f6870d77dd4c00e7e720c0.zip
Merge branch 'master' into core-updates
Conflicts: gnu/packages/image.scm
Diffstat (limited to 'gnu/build')
-rw-r--r--gnu/build/activation.scm82
-rw-r--r--gnu/build/install.scm46
-rw-r--r--gnu/build/linux-boot.scm14
-rw-r--r--gnu/build/linux-initrd.scm72
4 files changed, 163 insertions, 51 deletions
diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm
index 362669cbf9..04dd19f3e1 100644
--- a/gnu/build/activation.scm
+++ b/gnu/build/activation.scm
@@ -26,6 +26,7 @@
#:export (activate-users+groups
activate-etc
activate-setuid-programs
+ activate-/bin/sh
activate-current-system))
;;; Commentary:
@@ -146,48 +147,64 @@ numeric gid or #f."
;; /etc is a mixture of static and dynamic settings. Here is where we
;; initialize it from the static part.
+ (define (rm-f file)
+ (false-if-exception (delete-file file)))
+
(format #t "populating /etc from ~a...~%" etc)
- (let ((rm-f (lambda (f)
- (false-if-exception (delete-file f)))))
- (rm-f "/etc/static")
- (symlink etc "/etc/static")
- (for-each (lambda (file)
- ;; TODO: Handle 'shadow' specially so that changed
- ;; password aren't lost.
- (let ((target (string-append "/etc/" file))
- (source (string-append "/etc/static/" file)))
- (rm-f target)
- (symlink source target)))
- (scandir etc
- (lambda (file)
- (not (member file '("." ".."))))
-
- ;; The default is 'string-locale<?', but we don't have
- ;; it when run from the initrd's statically-linked
- ;; Guile.
- string<?))
-
- ;; Prevent ETC from being GC'd.
- (rm-f "/var/guix/gcroots/etc-directory")
- (symlink etc "/var/guix/gcroots/etc-directory")))
+
+ (rm-f "/etc/static")
+ (symlink etc "/etc/static")
+ (for-each (lambda (file)
+ (let ((target (string-append "/etc/" file))
+ (source (string-append "/etc/static/" file)))
+ (rm-f target)
+
+ ;; Things such as /etc/sudoers must be regular files, not
+ ;; symlinks; furthermore, they could be modified behind our
+ ;; back---e.g., with 'visudo'. Thus, make a copy instead of
+ ;; symlinking them.
+ (if (file-is-directory? source)
+ (symlink source target)
+ (copy-file source target))
+
+ ;; XXX: Dirty hack to meet sudo's expectations.
+ (when (string=? (basename target) "sudoers")
+ (chmod target #o440))))
+ (scandir etc
+ (lambda (file)
+ (not (member file '("." ".."))))
+
+ ;; The default is 'string-locale<?', but we don't have
+ ;; it when run from the initrd's statically-linked
+ ;; Guile.
+ string<?))
+
+ ;; Prevent ETC from being GC'd.
+ (rm-f "/var/guix/gcroots/etc-directory")
+ (symlink etc "/var/guix/gcroots/etc-directory"))
(define %setuid-directory
;; Place where setuid programs are stored.
"/run/setuid-programs")
+(define (link-or-copy source target)
+ "Attempt to make TARGET a hard link to SOURCE; if it fails, fall back to
+copy SOURCE to TARGET."
+ (catch 'system-error
+ (lambda ()
+ (link source target))
+ (lambda args
+ ;; Perhaps SOURCE and TARGET live in a different file system, so copy
+ ;; SOURCE.
+ (copy-file source target))))
+
(define (activate-setuid-programs programs)
"Turn PROGRAMS, a list of file names, into setuid programs stored under
%SETUID-DIRECTORY."
(define (make-setuid-program prog)
(let ((target (string-append %setuid-directory
"/" (basename prog))))
- (catch 'system-error
- (lambda ()
- (link prog target))
- (lambda args
- ;; Perhaps PROG and TARGET live in a different file system, so copy
- ;; PROG.
- (copy-file prog target)))
+ (link-or-copy prog target)
(chown target 0 0)
(chmod target #o6555)))
@@ -204,6 +221,11 @@ numeric gid or #f."
(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 %current-system
;; The system that is current (a symlink.) This is not necessarily the same
;; as the system we booted (aka. /run/booted-system) because we can re-build
diff --git a/gnu/build/install.scm b/gnu/build/install.scm
index e16896f8b8..a472259a4a 100644
--- a/gnu/build/install.scm
+++ b/gnu/build/install.scm
@@ -56,18 +56,38 @@ MOUNT-POINT."
"Evaluate DIRECTIVE, an sexp describing a file or directory to create under
directory TARGET."
(let loop ((directive directive))
- (match directive
- (('directory name)
- (mkdir-p (string-append target name)))
- (('directory name uid gid)
- (let ((dir (string-append target name)))
- (mkdir-p dir)
- (chown dir uid gid)))
- (('directory name uid gid mode)
- (loop `(directory ,name ,uid ,gid))
- (chmod (string-append target name) mode))
- ((new '-> old)
- (symlink old (string-append target new))))))
+ (catch 'system-error
+ (lambda ()
+ (match directive
+ (('directory name)
+ (mkdir-p (string-append target name)))
+ (('directory name uid gid)
+ (let ((dir (string-append target name)))
+ (mkdir-p dir)
+ (chown dir uid gid)))
+ (('directory name uid gid mode)
+ (loop `(directory ,name ,uid ,gid))
+ (chmod (string-append target name) mode))
+ ((new '-> old)
+ (let try ()
+ (catch 'system-error
+ (lambda ()
+ (symlink old (string-append target new)))
+ (lambda args
+ ;; When doing 'guix system init' on the current '/', some
+ ;; symlinks may already exists. Override them.
+ (if (= EEXIST (system-error-errno args))
+ (begin
+ (delete-file (string-append target new))
+ (try))
+ (apply throw args))))))))
+ (lambda args
+ ;; Usually we can only get here when installing to an existing root,
+ ;; as with 'guix system init foo.scm /'.
+ (format (current-error-port)
+ "error: failed to evaluate directive: ~s~%"
+ directive)
+ (apply throw args)))))
(define (directives store)
"Return a list of directives to populate the root file system that will host
@@ -93,7 +113,6 @@ STORE."
("/var/guix/gcroots/current-system" -> "/run/current-system")
(directory "/bin")
- ("/bin/sh" -> "/run/current-system/profile/bin/bash")
(directory "/tmp" 0 0 #o1777) ; sticky bit
(directory "/root" 0 0) ; an exception
@@ -106,6 +125,7 @@ includes /etc, /var, /run, /bin/sh, etc., and all the symlinks to SYSTEM."
(directives (%store-directory)))
;; Add system generation 1.
+ (false-if-exception (delete-file "/var/guix/profiles/system-1-link"))
(symlink system
(string-append target "/var/guix/profiles/system-1-link")))
diff --git a/gnu/build/linux-boot.scm b/gnu/build/linux-boot.scm
index 21ee58ad50..fbc683c798 100644
--- a/gnu/build/linux-boot.scm
+++ b/gnu/build/linux-boot.scm
@@ -221,6 +221,7 @@ networking values.) Return #t if INTERFACE is up, #f otherwise."
(define (load-linux-module* file)
"Load Linux module from FILE, the name of a `.ko' file."
(define (slurp module)
+ ;; TODO: Use 'mmap' to reduce memory usage.
(call-with-input-file file get-bytevector-all))
(load-linux-module (slurp file)))
@@ -342,10 +343,11 @@ bailing out.~%root contents: ~s~%" (scandir "/"))
volatile-root?
(mounts '()))
"This procedure is meant to be called from an initrd. Boot a system by
-first loading LINUX-MODULES, then setting up QEMU guest networking if
-QEMU-GUEST-NETWORKING? is true, mounting the file systems specified in MOUNTS,
-and finally booting into the new root if any. The initrd supports kernel
-command-line options '--load', '--root', and '--repl'.
+first loading LINUX-MODULES (a list of absolute file names of '.ko' files),
+then setting up QEMU guest networking if QEMU-GUEST-NETWORKING? is true,
+mounting the file systems specified in MOUNTS, and finally booting into the
+new root if any. The initrd supports kernel command-line options '--load',
+'--root', and '--repl'.
Mount the root file system, specified by the '--root' command-line argument,
if any.
@@ -383,9 +385,7 @@ to it are lost."
(start-repl))
(display "loading kernel modules...\n")
- (for-each (compose load-linux-module*
- (cut string-append "/modules/" <>))
- linux-modules)
+ (for-each load-linux-module* linux-modules)
(when qemu-guest-networking?
(unless (configure-qemu-networking)
diff --git a/gnu/build/linux-initrd.scm b/gnu/build/linux-initrd.scm
index bf60137e8f..54639bd319 100644
--- a/gnu/build/linux-initrd.scm
+++ b/gnu/build/linux-initrd.scm
@@ -17,9 +17,15 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu build linux-initrd)
+ #:use-module (guix build utils)
+ #:use-module (guix build store-copy)
+ #:use-module (system base compile)
+ #:use-module (rnrs bytevectors)
+ #:use-module ((system foreign) #:select (sizeof))
#:use-module (ice-9 popen)
#:use-module (ice-9 ftw)
- #:export (write-cpio-archive))
+ #:export (write-cpio-archive
+ build-initrd))
;;; Commentary:
;;;
@@ -69,4 +75,68 @@ COMPRESS? is true, compress it using GZIP. On success, return OUTPUT."
output))
output))))
+(define (cache-compiled-file-name file)
+ "Return the file name of the in-cache .go file for FILE, relative to the
+current directory.
+
+This is similar to what 'compiled-file-name' in (system base compile) does."
+ (let loop ((file file))
+ (let ((target (false-if-exception (readlink file))))
+ (if target
+ (loop target)
+ (format #f ".cache/guile/ccache/~a-~a-~a-~a/~a"
+ (effective-version)
+ (if (eq? (native-endianness) (endianness little))
+ "LE"
+ "BE")
+ (sizeof '*)
+ (effective-version)
+ file)))))
+
+(define (compile-to-cache file)
+ "Compile FILE to the cache."
+ (let ((compiled-file (cache-compiled-file-name file)))
+ (mkdir-p (dirname compiled-file))
+ (compile-file file
+ #:opts %auto-compilation-options
+ #:output-file compiled-file)))
+
+(define* (build-initrd output
+ #:key
+ guile init
+ (references-graphs '())
+ (cpio "cpio")
+ (gzip "gzip"))
+ "Write an initial RAM disk (initrd) to OUTPUT. The initrd starts the script
+at INIT, running GUILE. It contains all the items referred to by
+REFERENCES-GRAPHS."
+ (mkdir "contents")
+
+ ;; Copy the closures of all the items referenced in REFERENCES-GRAPHS.
+ (populate-store references-graphs "contents")
+
+ (with-directory-excursion "contents"
+ ;; Make '/init'.
+ (symlink init "init")
+
+ ;; Compile it.
+ (compile-to-cache "init")
+
+ ;; Allow Guile to find out where it is (XXX). See
+ ;; 'guile-relocatable.patch'.
+ (mkdir-p "proc/self")
+ (symlink (string-append guile "/bin/guile") "proc/self/exe")
+ (readlink "proc/self/exe")
+
+ ;; Reset the timestamps of all the files that will make it in the initrd.
+ (for-each (lambda (file)
+ (unless (eq? 'symlink (stat:type (lstat file)))
+ (utime file 0 0 0 0)))
+ (find-files "." ".*"))
+
+ (write-cpio-archive output "."
+ #:cpio cpio #:gzip gzip))
+
+ (delete-file-recursively "contents"))
+
;;; linux-initrd.scm ends here