gnu: Add glm.
[jackhill/guix/guix.git] / gnu / build / linux-initrd.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
3 ;;;
4 ;;; This file is part of GNU Guix.
5 ;;;
6 ;;; GNU Guix is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
10 ;;;
11 ;;; GNU Guix is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;; GNU General Public License for more details.
15 ;;;
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19 (define-module (gnu build linux-initrd)
20 #:use-module (guix build utils)
21 #:use-module (guix build store-copy)
22 #:use-module (system base compile)
23 #:use-module (rnrs bytevectors)
24 #:use-module ((system foreign) #:select (sizeof))
25 #:use-module (ice-9 popen)
26 #:use-module (ice-9 ftw)
27 #:export (write-cpio-archive
28 build-initrd))
29
30 ;;; Commentary:
31 ;;;
32 ;;; Tools to create Linux initial RAM disks ("initrds"). Initrds are
33 ;;; essentially gzipped cpio archives, with a '/init' executable that the
34 ;;; kernel runs at boot time.
35 ;;;
36 ;;; Code:
37
38 (define* (write-cpio-archive output directory
39 #:key
40 (compress? #t)
41 (cpio "cpio") (gzip "gzip"))
42 "Write a cpio archive containing DIRECTORY to file OUTPUT, using CPIO. When
43 COMPRESS? is true, compress it using GZIP. On success, return OUTPUT."
44
45 ;; Note: don't use '--no-absolute-filenames' since that strips leading
46 ;; slashes from symlink targets.
47 (let ((pipe (open-pipe* OPEN_WRITE cpio "-o" "-O" output
48 "-H" "newc" "--null")))
49 (define (print0 file)
50 (format pipe "~a\0" file))
51
52 ;; Note: as per `ramfs-rootfs-initramfs.txt', always add directory entries
53 ;; before the files that are inside of it: "The Linux kernel cpio
54 ;; extractor won't create files in a directory that doesn't exist, so the
55 ;; directory entries must go before the files that go in those
56 ;; directories."
57
58 ;; XXX: Use a deterministic order.
59 (file-system-fold (const #t)
60 (lambda (file stat result) ; leaf
61 (print0 file))
62 (lambda (dir stat result) ; down
63 (unless (string=? dir directory)
64 (print0 dir)))
65 (const #f) ; up
66 (const #f) ; skip
67 (const #f)
68 #f
69 directory)
70
71 (and (zero? (close-pipe pipe))
72 (or (not compress?)
73 (and (zero? (system* gzip "--best" output))
74 (rename-file (string-append output ".gz")
75 output))
76 output))))
77
78 (define (cache-compiled-file-name file)
79 "Return the file name of the in-cache .go file for FILE, relative to the
80 current directory.
81
82 This is similar to what 'compiled-file-name' in (system base compile) does."
83 (let loop ((file file))
84 (let ((target (false-if-exception (readlink file))))
85 (if target
86 (loop target)
87 (format #f ".cache/guile/ccache/~a-~a-~a-~a/~a"
88 (effective-version)
89 (if (eq? (native-endianness) (endianness little))
90 "LE"
91 "BE")
92 (sizeof '*)
93 (effective-version)
94 file)))))
95
96 (define (compile-to-cache file)
97 "Compile FILE to the cache."
98 (let ((compiled-file (cache-compiled-file-name file)))
99 (mkdir-p (dirname compiled-file))
100 (compile-file file
101 #:opts %auto-compilation-options
102 #:output-file compiled-file)))
103
104 (define* (build-initrd output
105 #:key
106 guile init
107 (references-graphs '())
108 (cpio "cpio")
109 (gzip "gzip"))
110 "Write an initial RAM disk (initrd) to OUTPUT. The initrd starts the script
111 at INIT, running GUILE. It contains all the items referred to by
112 REFERENCES-GRAPHS."
113 (mkdir "contents")
114
115 ;; Copy the closures of all the items referenced in REFERENCES-GRAPHS.
116 (populate-store references-graphs "contents")
117
118 (with-directory-excursion "contents"
119 ;; Make '/init'.
120 (symlink init "init")
121
122 ;; Compile it.
123 (compile-to-cache "init")
124
125 ;; Allow Guile to find out where it is (XXX). See
126 ;; 'guile-relocatable.patch'.
127 (mkdir-p "proc/self")
128 (symlink (string-append guile "/bin/guile") "proc/self/exe")
129 (readlink "proc/self/exe")
130
131 ;; Reset the timestamps of all the files that will make it in the initrd.
132 (for-each (lambda (file)
133 (unless (eq? 'symlink (stat:type (lstat file)))
134 (utime file 0 0 0 0)))
135 (find-files "." ".*"))
136
137 (write-cpio-archive output "."
138 #:cpio cpio #:gzip gzip))
139
140 (delete-file-recursively "contents"))
141
142 ;;; linux-initrd.scm ends here