image: Add a new API.
[jackhill/guix/guix.git] / gnu / build / install.scm
CommitLineData
5ce3defe 1;;; GNU Guix --- Functional package management for GNU
0ae735bc 2;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 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)
5ce3defe 21 #:use-module (guix build utils)
9d3fb6c7 22 #:use-module (guix build store-copy)
b4140694 23 #:use-module (srfi srfi-26)
5ce3defe 24 #:use-module (ice-9 match)
9121ce55 25 #:export (install-boot-config
5895ec8a 26 evaluate-populate-directive
b4140694 27 populate-root-file-system
c5ce2db5 28 install-database-and-gc-roots
9d3fb6c7 29 populate-single-profile-directory))
5ce3defe
LC
30
31;;; Commentary:
32;;;
33;;; This module supports the installation of the GNU system on a hard disk.
34;;; It is meant to be used both in a build environment (in derivations that
35;;; build VM images), and on the bare metal (when really installing the
36;;; system.)
37;;;
38;;; Code:
39
9121ce55
MO
40(define (install-boot-config bootcfg bootcfg-location mount-point)
41 "Atomically copy BOOTCFG into BOOTCFG-LOCATION on the MOUNT-POINT. Note
42that the caller must make sure that BOOTCFG is registered as a GC root so
43that the fonts, background images, etc. referred to by BOOTCFG are not GC'd."
44 (let* ((target (string-append mount-point bootcfg-location))
6ffd11f1
LC
45 (pivot (string-append target ".new")))
46 (mkdir-p (dirname target))
47
9121ce55 48 ;; Copy BOOTCFG instead of just symlinking it, because symlinks won't
6412e58a 49 ;; work when /boot is on a separate partition. Do that atomically.
9121ce55 50 (copy-file bootcfg pivot)
1e17a2d5 51 (rename-file pivot target)))
5ce3defe 52
5990e95b
MO
53(define* (evaluate-populate-directive directive target
54 #:key
55 (default-gid 0)
56 (default-uid 0))
5ce3defe 57 "Evaluate DIRECTIVE, an sexp describing a file or directory to create under
5990e95b
MO
58directory TARGET. DEFAULT-UID and DEFAULT-GID are the default UID and GID in
59the context of the caller. If the directive matches those defaults then,
60'chown' won't be run."
b4140694 61 (let loop ((directive directive))
a4888e2e
LC
62 (catch 'system-error
63 (lambda ()
64 (match directive
65 (('directory name)
66 (mkdir-p (string-append target name)))
67 (('directory name uid gid)
68 (let ((dir (string-append target name)))
69 (mkdir-p dir)
5990e95b
MO
70 ;; If called from a context without "root" permissions, "chown"
71 ;; to root will fail. In that case, do not try to run "chown"
72 ;; and assume that the file will be chowned elsewhere (when
73 ;; interned in the store for instance).
74 (or (and (= uid default-uid) (= gid default-gid))
75 (chown dir uid gid))))
a4888e2e
LC
76 (('directory name uid gid mode)
77 (loop `(directory ,name ,uid ,gid))
78 (chmod (string-append target name) mode))
79 ((new '-> old)
80 (let try ()
81 (catch 'system-error
82 (lambda ()
83 (symlink old (string-append target new)))
84 (lambda args
85 ;; When doing 'guix system init' on the current '/', some
86 ;; symlinks may already exists. Override them.
87 (if (= EEXIST (system-error-errno args))
88 (begin
89 (delete-file (string-append target new))
90 (try))
91 (apply throw args))))))))
92 (lambda args
93 ;; Usually we can only get here when installing to an existing root,
94 ;; as with 'guix system init foo.scm /'.
95 (format (current-error-port)
96 "error: failed to evaluate directive: ~s~%"
97 directive)
98 (apply throw args)))))
b4140694
LC
99
100(define (directives store)
101 "Return a list of directives to populate the root file system that will host
102STORE."
892bbea7 103 `((directory ,store 0 0 #o1775)
185f6691 104
b4140694 105 (directory "/etc")
171a0a13 106 (directory "/var/log") ; for shepherd
b4140694 107 (directory "/var/guix/gcroots")
517830cc 108 (directory "/var/empty") ; for no-login accounts
3485716f 109 (directory "/var/db") ; for dhclient, etc.
4b2615e1 110 (directory "/var/run")
b4140694 111 (directory "/run")
3485716f 112 (directory "/mnt")
f2c403ea
LC
113 (directory "/var/guix/profiles/per-user/root" 0 0)
114
115 ;; Link to the initial system generation.
116 ("/var/guix/profiles/system" -> "system-1-link")
117
b4140694
LC
118 ("/var/guix/gcroots/booted-system" -> "/run/booted-system")
119 ("/var/guix/gcroots/current-system" -> "/run/current-system")
334bda9a
LC
120 ("/var/guix/gcroots/profiles" -> "/var/guix/profiles")
121
b4140694 122 (directory "/bin")
b4140694 123 (directory "/tmp" 0 0 #o1777) ; sticky bit
f73b8e3d 124 (directory "/var/tmp" 0 0 #o1777)
d9c41939 125 (directory "/var/lock" 0 0 #o1777)
b4140694 126
b4140694
LC
127 (directory "/home" 0 0)))
128
f2c403ea 129(define (populate-root-file-system system target)
b4140694 130 "Make the essential non-store files and directories on TARGET. This
f2c403ea 131includes /etc, /var, /run, /bin/sh, etc., and all the symlinks to SYSTEM."
b4140694 132 (for-each (cut evaluate-populate-directive <> target)
f2c403ea
LC
133 (directives (%store-directory)))
134
135 ;; Add system generation 1.
aea9b232
LC
136 (let ((generation-1 (string-append target
137 "/var/guix/profiles/system-1-link")))
138 (let try ()
139 (catch 'system-error
140 (lambda ()
141 (symlink system generation-1))
142 (lambda args
143 ;; If GENERATION-1 already exists, overwrite it.
144 (if (= EEXIST (system-error-errno args))
145 (begin
146 (delete-file generation-1)
147 (try))
148 (apply throw args)))))))
5ce3defe 149
c5ce2db5
LC
150(define %root-profile
151 "/var/guix/profiles/per-user/root")
152
153(define* (install-database-and-gc-roots root database profile
154 #:key (profile-name "guix-profile"))
155 "Install DATABASE, the store database, under directory ROOT. Create
156PROFILE-NAME and have it link to PROFILE, a store item."
157 (define (scope file)
158 (string-append root "/" file))
159
160 (define (mkdir-p* dir)
161 (mkdir-p (scope dir)))
162
163 (define (symlink* old new)
164 (symlink old (scope new)))
165
166 (install-file database (scope "/var/guix/db/"))
167 (chmod (scope "/var/guix/db/db.sqlite") #o644)
168 (mkdir-p* "/var/guix/profiles")
169 (mkdir-p* "/var/guix/gcroots")
170 (symlink* "/var/guix/profiles" "/var/guix/gcroots/profiles")
171
172 ;; Make root's profile, which makes it a GC root.
173 (mkdir-p* %root-profile)
174 (symlink* profile
175 (string-append %root-profile "/" profile-name "-1-link"))
176 (symlink* (string-append profile-name "-1-link")
177 (string-append %root-profile "/" profile-name)))
178
9d3fb6c7 179(define* (populate-single-profile-directory directory
08fa7613 180 #:key profile closure
ab3c60ac 181 (profile-name "guix-profile")
ec4c81fe 182 database)
9d3fb6c7
LC
183 "Populate DIRECTORY with a store containing PROFILE, whose closure is given
184in the file called CLOSURE (as generated by #:references-graphs.) DIRECTORY
185is initialized to contain a single profile under /root pointing to PROFILE.
ec4c81fe
LC
186
187When DATABASE is true, copy it to DIRECTORY/var/guix/db and create
188DIRECTORY/var/guix/gcroots and friends.
08fa7613 189
ab3c60ac
LC
190PROFILE-NAME is the name of the profile being created under
191/var/guix/profiles, typically either \"guix-profile\" or \"current-guix\".
192
6b63c43e 193This is used to create the self-contained tarballs with 'guix pack'."
9d3fb6c7
LC
194 (define (scope file)
195 (string-append directory "/" file))
196
9d3fb6c7
LC
197 (define (mkdir-p* dir)
198 (mkdir-p (scope dir)))
199
200 (define (symlink* old new)
201 (symlink old (scope new)))
202
203 ;; Populate the store.
204 (populate-store (list closure) directory)
6b63c43e 205
ec4c81fe 206 (when database
c5ce2db5
LC
207 (install-database-and-gc-roots directory database profile
208 #:profile-name profile-name))
ab3c60ac
LC
209
210 (match profile-name
211 ("guix-profile"
212 (mkdir-p* "/root")
213 (symlink* (string-append %root-profile "/guix-profile")
214 "/root/.guix-profile"))
215 ("current-guix"
216 (mkdir-p* "/root/.config/guix")
217 (symlink* (string-append %root-profile "/current-guix")
218 "/root/.config/guix/current"))
219 (_
220 #t)))
9d3fb6c7 221
5ce3defe 222;;; install.scm ends here