summaryrefslogtreecommitdiff
path: root/gnu/installer/final.scm
diff options
context:
space:
mode:
authorMathieu Othacehe <othacehe@gnu.org>2020-08-13 14:16:12 +0200
committerMathieu Othacehe <othacehe@gnu.org>2020-09-02 17:05:23 +0200
commit8ce6f4dc2879919c12bc76a2f4b01200af97e019 (patch)
treebcdfea85d25af8ae24622310a035688ac8257dcc /gnu/installer/final.scm
parent5316dfc0f125b658e4a2acf7f00f49501663d943 (diff)
installer: Run the installation inside a container.
When the store overlay is mounted, other processes such as kmscon, udev and guix-daemon may open files from the store, preventing the underlying install support from being umounted. See: https://lists.gnu.org/archive/html/guix-devel/2018-12/msg00161.html. To avoid this situation, mount the store overlay inside a container, and run the installation from within that container. * gnu/build/shepherd.scm (fork+exec-command/container): New procedure. * gnu/services/base.scm (guix-shepherd-service): Support an optional PID argument passed to the "start" method. If that argument is passed, ensure that guix-daemon enters the given PID MNT namespace by using fork+exec-command/container procedure. * gnu/installer/final.scm (umount-cow-store): Remove it, (install-system): run the installation from within a container. * gnu/installer/newt/final.scm (run-install-shell): Remove the display hack.
Diffstat (limited to 'gnu/installer/final.scm')
-rw-r--r--gnu/installer/final.scm124
1 files changed, 61 insertions, 63 deletions
diff --git a/gnu/installer/final.scm b/gnu/installer/final.scm
index 685aa81d89b..11143b2adbe 100644
--- a/gnu/installer/final.scm
+++ b/gnu/installer/final.scm
@@ -26,6 +26,8 @@
26 #:use-module (guix build syscalls) 26 #:use-module (guix build syscalls)
27 #:use-module (guix build utils) 27 #:use-module (guix build utils)
28 #:use-module (gnu build accounts) 28 #:use-module (gnu build accounts)
29 #:use-module (gnu build install)
30 #:use-module (gnu build linux-container)
29 #:use-module ((gnu system shadow) #:prefix sys:) 31 #:use-module ((gnu system shadow) #:prefix sys:)
30 #:use-module (rnrs io ports) 32 #:use-module (rnrs io ports)
31 #:use-module (srfi srfi-1) 33 #:use-module (srfi srfi-1)
@@ -133,49 +135,18 @@ USERS."
133 (_ #f)))))) 135 (_ #f))))))
134 pids))) 136 pids)))
135 137
136(define (umount-cow-store)
137 "Remove the store overlay and the bind-mount on /tmp created by the
138cow-store service. This procedure is very fragile and a better approach would
139be much appreciated."
140 (catch #t
141 (lambda ()
142 (let ((tmp-dir "/remove"))
143 (syslog "Unmounting cow-store.~%")
144
145 (mkdir-p tmp-dir)
146 (mount (%store-directory) tmp-dir "" MS_MOVE)
147
148 ;; The guix-daemon has possibly opened files from the cow-store,
149 ;; restart it.
150 (restart-service 'guix-daemon)
151
152 (syslog "Killing cow users.")
153
154 ;; Kill all processes started while the cow-store was active (logins
155 ;; on other TTYs for instance).
156 (kill-cow-users tmp-dir)
157
158 ;; Try to umount the store overlay. Some process such as udevd
159 ;; workers might still be active, so do some retries.
160 (let loop ((try 5))
161 (syslog "Umount try ~a~%" (- 5 try))
162 (sleep 1)
163 (let ((umounted? (false-if-exception (umount tmp-dir))))
164 (if (and (not umounted?) (> try 0))
165 (loop (- try 1))
166 (if umounted?
167 (syslog "Umounted ~a successfully.~%" tmp-dir)
168 (syslog "Failed to umount ~a.~%" tmp-dir)))))
169
170 (umount "/tmp")))
171 (lambda args
172 (syslog "~a~%" args))))
173
174(define* (install-system locale #:key (users '())) 138(define* (install-system locale #:key (users '()))
175 "Create /etc/shadow and /etc/passwd on the installation target for USERS. 139 "Create /etc/shadow and /etc/passwd on the installation target for USERS.
176Start COW-STORE service on target directory and launch guix install command in 140Start COW-STORE service on target directory and launch guix install command in
177a subshell. LOCALE must be the locale name under which that command will run, 141a subshell. LOCALE must be the locale name under which that command will run,
178or #f. Return #t on success and #f on failure." 142or #f. Return #t on success and #f on failure."
143 (define backing-directory
144 ;; Sub-directory used as the backing store for copy-on-write.
145 "/tmp/guix-inst")
146
147 (define (assert-exit x)
148 (primitive-exit (if x 0 1)))
149
179 (let* ((options (catch 'system-error 150 (let* ((options (catch 'system-error
180 (lambda () 151 (lambda ()
181 ;; If this file exists, it can provide 152 ;; If this file exists, it can provide
@@ -188,7 +159,11 @@ or #f. Return #t on success and #f on failure."
188 "--fallback") 159 "--fallback")
189 options 160 options
190 (list (%installer-configuration-file) 161 (list (%installer-configuration-file)
191 (%installer-target-dir))))) 162 (%installer-target-dir))))
163 (database-dir "/var/guix/db")
164 (database-file (string-append database-dir "/db.sqlite"))
165 (saved-database (string-append database-dir "/db.save"))
166 (ret #f))
192 (mkdir-p (%installer-target-dir)) 167 (mkdir-p (%installer-target-dir))
193 168
194 ;; We want to initialize user passwords but we don't want to store them in 169 ;; We want to initialize user passwords but we don't want to store them in
@@ -198,27 +173,50 @@ or #f. Return #t on success and #f on failure."
198 ;; passwords that we've put in there. 173 ;; passwords that we've put in there.
199 (create-user-database users (%installer-target-dir)) 174 (create-user-database users (%installer-target-dir))
200 175
201 (dynamic-wind 176 ;; When the store overlay is mounted, other processes such as kmscon, udev
202 (lambda () 177 ;; and guix-daemon may open files from the store, preventing the
203 (start-service 'cow-store (list (%installer-target-dir)))) 178 ;; underlying install support from being umounted. See:
204 (lambda () 179 ;; https://lists.gnu.org/archive/html/guix-devel/2018-12/msg00161.html.
205 ;; If there are any connected clients, assume that we are running 180 ;;
206 ;; installation tests. In that case, dump the standard and error 181 ;; To avoid this situation, mount the store overlay inside a container,
207 ;; outputs to syslog. 182 ;; and run the installation from within that container.
208 (if (not (null? (current-clients))) 183 (zero?
209 (with-output-to-file "/dev/console" 184 (call-with-container '()
210 (lambda () 185 (lambda ()
211 (with-error-to-file "/dev/console" 186 (dynamic-wind
212 (lambda () 187 (lambda ()
213 (setvbuf (current-output-port) 'none) 188 ;; Save the database, so that it can be restored once the
214 (setvbuf (current-error-port) 'none) 189 ;; cow-store is umounted.
215 (run-command install-command #:locale locale))))) 190 (copy-file database-file saved-database)
216 (run-command install-command #:locale locale))) 191 (mount-cow-store (%installer-target-dir) backing-directory))
217 (lambda () 192 (lambda ()
218 (stop-service 'cow-store) 193 ;; We need to drag the guix-daemon to the container MNT
219 ;; Remove the store overlay created at cow-store service start. 194 ;; namespace, so that it can operate on the cow-store.
220 ;; Failing to do that will result in further umount calls to fail 195 (stop-service 'guix-daemon)
221 ;; because the target device is seen as busy. See: 196 (start-service 'guix-daemon (list (number->string (getpid))))
222 ;; https://lists.gnu.org/archive/html/guix-devel/2018-12/msg00161.html. 197
223 (umount-cow-store) 198 (setvbuf (current-output-port) 'none)
224 #f)))) 199 (setvbuf (current-error-port) 'none)
200
201 ;; If there are any connected clients, assume that we are running
202 ;; installation tests. In that case, dump the standard and error
203 ;; outputs to syslog.
204 (set! ret
205 (if (not (null? (current-clients)))
206 (with-output-to-file "/dev/console"
207 (lambda ()
208 (with-error-to-file "/dev/console"
209 (lambda ()
210 (run-command install-command
211 #:locale locale)))))
212 (run-command install-command #:locale locale))))
213 (lambda ()
214 ;; Restart guix-daemon so that it does no keep the MNT namespace
215 ;; alive.
216 (restart-service 'guix-daemon)
217 (copy-file saved-database database-file)
218
219 ;; Finally umount the cow-store and exit the container.
220 (unmount-cow-store (%installer-target-dir) backing-directory)
221 (assert-exit ret))))
222 #:namespaces '(mnt)))))