Merge branch 'master' into staging
[jackhill/guix/guix.git] / gnu / build / install.scm
CommitLineData
5ce3defe 1;;; GNU Guix --- Functional package management for GNU
87241947 2;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
1e17a2d5 3;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
5ce3defe
LC
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
548f7a8f 20(define-module (gnu build install)
22827396 21 #:use-module (guix build syscalls)
5ce3defe 22 #:use-module (guix build utils)
9d3fb6c7 23 #:use-module (guix build store-copy)
b4140694 24 #:use-module (srfi srfi-26)
5ce3defe 25 #:use-module (ice-9 match)
9121ce55 26 #:export (install-boot-config
5895ec8a 27 evaluate-populate-directive
b4140694 28 populate-root-file-system
c5ce2db5 29 install-database-and-gc-roots
22827396
MO
30 populate-single-profile-directory
31 mount-cow-store
32 unmount-cow-store))
5ce3defe
LC
33
34;;; Commentary:
35;;;
36;;; This module supports the installation of the GNU system on a hard disk.
37;;; It is meant to be used both in a build environment (in derivations that
38;;; build VM images), and on the bare metal (when really installing the
39;;; system.)
40;;;
41;;; Code:
42
9121ce55
MO
43(define (install-boot-config bootcfg bootcfg-location mount-point)
44 "Atomically copy BOOTCFG into BOOTCFG-LOCATION on the MOUNT-POINT. Note
45that the caller must make sure that BOOTCFG is registered as a GC root so
46that the fonts, background images, etc. referred to by BOOTCFG are not GC'd."
47 (let* ((target (string-append mount-point bootcfg-location))
6ffd11f1
LC
48 (pivot (string-append target ".new")))
49 (mkdir-p (dirname target))
50
9121ce55 51 ;; Copy BOOTCFG instead of just symlinking it, because symlinks won't
6412e58a 52 ;; work when /boot is on a separate partition. Do that atomically.
9121ce55 53 (copy-file bootcfg pivot)
1e17a2d5 54 (rename-file pivot target)))
5ce3defe 55
5990e95b
MO
56(define* (evaluate-populate-directive directive target
57 #:key
58 (default-gid 0)
59 (default-uid 0))
5ce3defe 60 "Evaluate DIRECTIVE, an sexp describing a file or directory to create under
5990e95b
MO
61directory TARGET. DEFAULT-UID and DEFAULT-GID are the default UID and GID in
62the context of the caller. If the directive matches those defaults then,
63'chown' won't be run."
b4140694 64 (let loop ((directive directive))
a4888e2e
LC
65 (catch 'system-error
66 (lambda ()
67 (match directive
68 (('directory name)
69 (mkdir-p (string-append target name)))
70 (('directory name uid gid)
71 (let ((dir (string-append target name)))
72 (mkdir-p dir)
5990e95b
MO
73 ;; If called from a context without "root" permissions, "chown"
74 ;; to root will fail. In that case, do not try to run "chown"
75 ;; and assume that the file will be chowned elsewhere (when
76 ;; interned in the store for instance).
77 (or (and (= uid default-uid) (= gid default-gid))
78 (chown dir uid gid))))
a4888e2e
LC
79 (('directory name uid gid mode)
80 (loop `(directory ,name ,uid ,gid))
81 (chmod (string-append target name) mode))
87241947
LC
82 (('file name)
83 (call-with-output-file (string-append target name)
84 (const #t)))
85 (('file name (? string? content))
86 (call-with-output-file (string-append target name)
87 (lambda (port)
88 (display content port))))
a4888e2e
LC
89 ((new '-> old)
90 (let try ()
91 (catch 'system-error
92 (lambda ()
93 (symlink old (string-append target new)))
94 (lambda args
95 ;; When doing 'guix system init' on the current '/', some
96 ;; symlinks may already exists. Override them.
97 (if (= EEXIST (system-error-errno args))
98 (begin
99 (delete-file (string-append target new))
100 (try))
101 (apply throw args))))))))
102 (lambda args
103 ;; Usually we can only get here when installing to an existing root,
104 ;; as with 'guix system init foo.scm /'.
105 (format (current-error-port)
106 "error: failed to evaluate directive: ~s~%"
107 directive)
108 (apply throw args)))))
b4140694
LC
109
110(define (directives store)
111 "Return a list of directives to populate the root file system that will host
112STORE."
892bbea7 113 `((directory ,store 0 0 #o1775)
185f6691 114
b4140694 115 (directory "/etc")
171a0a13 116 (directory "/var/log") ; for shepherd
b4140694 117 (directory "/var/guix/gcroots")
517830cc 118 (directory "/var/empty") ; for no-login accounts
3485716f 119 (directory "/var/db") ; for dhclient, etc.
4b2615e1 120 (directory "/var/run")
b4140694 121 (directory "/run")
3485716f 122 (directory "/mnt")
f2c403ea
LC
123 (directory "/var/guix/profiles/per-user/root" 0 0)
124
125 ;; Link to the initial system generation.
126 ("/var/guix/profiles/system" -> "system-1-link")
127
b4140694
LC
128 ("/var/guix/gcroots/booted-system" -> "/run/booted-system")
129 ("/var/guix/gcroots/current-system" -> "/run/current-system")
334bda9a
LC
130 ("/var/guix/gcroots/profiles" -> "/var/guix/profiles")
131
b4140694 132 (directory "/bin")
b4140694 133 (directory "/tmp" 0 0 #o1777) ; sticky bit
f73b8e3d 134 (directory "/var/tmp" 0 0 #o1777)
d9c41939 135 (directory "/var/lock" 0 0 #o1777)
b4140694 136
b4140694
LC
137 (directory "/home" 0 0)))
138
87241947
LC
139(define* (populate-root-file-system system target
140 #:key (extras '()))
b4140694 141 "Make the essential non-store files and directories on TARGET. This
87241947
LC
142includes /etc, /var, /run, /bin/sh, etc., and all the symlinks to SYSTEM.
143EXTRAS is a list of directives appended to the built-in directives to populate
144TARGET."
b4140694 145 (for-each (cut evaluate-populate-directive <> target)
87241947 146 (append (directives (%store-directory)) extras))
f2c403ea
LC
147
148 ;; Add system generation 1.
aea9b232
LC
149 (let ((generation-1 (string-append target
150 "/var/guix/profiles/system-1-link")))
151 (let try ()
152 (catch 'system-error
153 (lambda ()
154 (symlink system generation-1))
155 (lambda args
156 ;; If GENERATION-1 already exists, overwrite it.
157 (if (= EEXIST (system-error-errno args))
158 (begin
159 (delete-file generation-1)
160 (try))
161 (apply throw args)))))))
5ce3defe 162
c5ce2db5
LC
163(define %root-profile
164 "/var/guix/profiles/per-user/root")
165
166(define* (install-database-and-gc-roots root database profile
167 #:key (profile-name "guix-profile"))
168 "Install DATABASE, the store database, under directory ROOT. Create
169PROFILE-NAME and have it link to PROFILE, a store item."
170 (define (scope file)
171 (string-append root "/" file))
172
173 (define (mkdir-p* dir)
174 (mkdir-p (scope dir)))
175
176 (define (symlink* old new)
177 (symlink old (scope new)))
178
179 (install-file database (scope "/var/guix/db/"))
180 (chmod (scope "/var/guix/db/db.sqlite") #o644)
181 (mkdir-p* "/var/guix/profiles")
182 (mkdir-p* "/var/guix/gcroots")
183 (symlink* "/var/guix/profiles" "/var/guix/gcroots/profiles")
184
185 ;; Make root's profile, which makes it a GC root.
186 (mkdir-p* %root-profile)
187 (symlink* profile
188 (string-append %root-profile "/" profile-name "-1-link"))
189 (symlink* (string-append profile-name "-1-link")
190 (string-append %root-profile "/" profile-name)))
191
9d3fb6c7 192(define* (populate-single-profile-directory directory
08fa7613 193 #:key profile closure
ab3c60ac 194 (profile-name "guix-profile")
ec4c81fe 195 database)
9d3fb6c7
LC
196 "Populate DIRECTORY with a store containing PROFILE, whose closure is given
197in the file called CLOSURE (as generated by #:references-graphs.) DIRECTORY
198is initialized to contain a single profile under /root pointing to PROFILE.
ec4c81fe
LC
199
200When DATABASE is true, copy it to DIRECTORY/var/guix/db and create
201DIRECTORY/var/guix/gcroots and friends.
08fa7613 202
ab3c60ac
LC
203PROFILE-NAME is the name of the profile being created under
204/var/guix/profiles, typically either \"guix-profile\" or \"current-guix\".
205
6b63c43e 206This is used to create the self-contained tarballs with 'guix pack'."
9d3fb6c7
LC
207 (define (scope file)
208 (string-append directory "/" file))
209
9d3fb6c7
LC
210 (define (mkdir-p* dir)
211 (mkdir-p (scope dir)))
212
213 (define (symlink* old new)
214 (symlink old (scope new)))
215
216 ;; Populate the store.
217 (populate-store (list closure) directory)
6b63c43e 218
ec4c81fe 219 (when database
c5ce2db5
LC
220 (install-database-and-gc-roots directory database profile
221 #:profile-name profile-name))
ab3c60ac
LC
222
223 (match profile-name
224 ("guix-profile"
225 (mkdir-p* "/root")
226 (symlink* (string-append %root-profile "/guix-profile")
227 "/root/.guix-profile"))
228 ("current-guix"
229 (mkdir-p* "/root/.config/guix")
230 (symlink* (string-append %root-profile "/current-guix")
231 "/root/.config/guix/current"))
232 (_
233 #t)))
9d3fb6c7 234
22827396
MO
235(define (mount-cow-store target backing-directory)
236 "Make the store copy-on-write, using TARGET as the backing store. This is
237useful when TARGET is on a hard disk, whereas the current store is on a RAM
238disk."
239 (define (set-store-permissions directory)
240 "Set the right perms on DIRECTORY to use it as the store."
241 (chown directory 0 30000) ;use the fixed 'guixbuild' GID
242 (chmod directory #o1775))
243
244 (let ((tmpdir (string-append target "/tmp")))
245 (mkdir-p tmpdir)
246 (mount tmpdir "/tmp" "none" MS_BIND))
247
248 (let* ((rw-dir (string-append target backing-directory))
249 (work-dir (string-append rw-dir "/../.overlayfs-workdir")))
250 (mkdir-p rw-dir)
251 (mkdir-p work-dir)
252 (mkdir-p "/.rw-store")
253 (set-store-permissions rw-dir)
254 (set-store-permissions "/.rw-store")
255
256 ;; Mount the overlay, then atomically make it the store.
257 (mount "none" "/.rw-store" "overlay" 0
258 (string-append "lowerdir=" (%store-directory) ","
259 "upperdir=" rw-dir ","
260 "workdir=" work-dir))
261 (mount "/.rw-store" (%store-directory) "" MS_MOVE)
262 (rmdir "/.rw-store")))
263
264(define (unmount-cow-store target backing-directory)
265 "Unmount copy-on-write store."
266 (let ((tmp-dir "/remove"))
267 (mkdir-p tmp-dir)
268 (mount (%store-directory) tmp-dir "" MS_MOVE)
269 (umount tmp-dir)
270 (rmdir tmp-dir)
271 (delete-file-recursively
272 (string-append target backing-directory))))
273
5ce3defe 274;;; install.scm ends here