summaryrefslogtreecommitdiff
path: root/gnu/build
diff options
context:
space:
mode:
authorChristopher Baines <mail@cbaines.net>2020-11-29 14:19:55 +0000
committerChristopher Baines <mail@cbaines.net>2020-11-29 17:34:18 +0000
commitff01206345e2306cc633db48e0b29eab9077091a (patch)
tree25c7ee17005dadc9bf4fae3f0873e03a4704f782 /gnu/build
parented2545f0fa0e2ad99d5a0c45f532c539b299b9fb (diff)
parent7c2e67400ffaef8eb6f30ef7126c976ee3d7e36c (diff)
downloadguix-patches-ff01206345e2306cc633db48e0b29eab9077091a.tar
guix-patches-ff01206345e2306cc633db48e0b29eab9077091a.tar.gz
Merge remote-tracking branch 'origin/master' into core-updates
Diffstat (limited to 'gnu/build')
-rw-r--r--gnu/build/bootloader.scm7
-rw-r--r--gnu/build/chromium-extension.scm192
-rw-r--r--gnu/build/file-systems.scm105
-rw-r--r--gnu/build/image.scm10
-rw-r--r--gnu/build/linux-boot.scm59
-rw-r--r--gnu/build/linux-initrd.scm13
-rw-r--r--gnu/build/shepherd.scm16
7 files changed, 382 insertions, 20 deletions
diff --git a/gnu/build/bootloader.scm b/gnu/build/bootloader.scm
index 5ec839f902..3916930c89 100644
--- a/gnu/build/bootloader.scm
+++ b/gnu/build/bootloader.scm
@@ -38,10 +38,13 @@
(lambda (input)
(let ((bv (get-bytevector-n input size)))
(call-with-port
+ ;; Do not use "call-with-output-file" that would truncate the file.
(open-file-output-port device
- (file-options no-truncate no-create)
+ (file-options no-truncate no-fail)
(buffer-mode block)
- (native-transcoder))
+ ;; Use the binary-friendly ISO-8859-1
+ ;; encoding.
+ (make-transcoder (latin-1-codec)))
(lambda (output)
(seek output offset SEEK_SET)
(put-bytevector output bv)))))))
diff --git a/gnu/build/chromium-extension.scm b/gnu/build/chromium-extension.scm
new file mode 100644
index 0000000000..d65df09f37
--- /dev/null
+++ b/gnu/build/chromium-extension.scm
@@ -0,0 +1,192 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Marius Bakke <marius@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu build chromium-extension)
+ #:use-module (gcrypt base16)
+ #:use-module ((gcrypt hash) #:prefix hash:)
+ #:use-module (ice-9 iconv)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module (gnu packages base)
+ #:use-module (gnu packages check)
+ #:use-module (gnu packages chromium)
+ #:use-module (gnu packages gnupg)
+ #:use-module (gnu packages tls)
+ #:use-module (gnu packages xorg)
+ #:use-module (guix build-system trivial)
+ #:export (make-chromium-extension))
+
+;;; Commentary:
+;;;
+;;; Tools to deal with Chromium extensions.
+;;;
+;;; Code:
+
+(define (make-signing-key seed)
+ "Return a derivation for a deterministic PKCS #8 private key using SEED."
+
+ (define sha256sum
+ (bytevector->base16-string (hash:sha256 (string->bytevector seed "UTF-8"))))
+
+ ;; certtool.c wants a 56 byte seed for a 2048 bit key.
+ (define size 2048)
+ (define normalized-seed (string-take sha256sum 56))
+
+ (computed-file (string-append seed "-signing-key.pem")
+ #~(system* #$(file-append gnutls "/bin/certtool")
+ "--generate-privkey"
+ "--key-type=rsa"
+ "--pkcs8"
+ ;; Use the provable FIPS-PUB186-4 algorithm for
+ ;; deterministic results.
+ "--provable"
+ "--password="
+ "--no-text"
+ (string-append "--bits=" #$(number->string size))
+ (string-append "--seed=" #$normalized-seed)
+ "--outfile" #$output)
+ #:local-build? #t))
+
+(define* (make-crx signing-key package #:optional (package-output "out"))
+ "Create a signed \".crx\" file from the unpacked Chromium extension residing
+in PACKAGE-OUTPUT of PACKAGE. The extension will be signed with SIGNING-KEY."
+ (define name (package-name package))
+ (define version (package-version package))
+
+ (with-imported-modules '((guix build utils))
+ (computed-file
+ (string-append name "-" version ".crx")
+ #~(begin
+ ;; This is not great. We pull Xorg and Chromium just to Zip and
+ ;; sign an extension. This should be implemented with something
+ ;; lighter. (TODO: where is the CRXv3 documentation..?)
+ (use-modules (guix build utils))
+ (let ((chromium #$(file-append ungoogled-chromium "/bin/chromium"))
+ (xvfb #$(file-append xorg-server "/bin/Xvfb"))
+ (packdir "/tmp/extension"))
+ (mkdir-p (dirname packdir))
+ (copy-recursively (ungexp package package-output) packdir)
+ (system (string-append xvfb " :1 &"))
+ (setenv "DISPLAY" ":1")
+ (sleep 2) ;give Xorg some time to initialize...
+ ;; Chromium stores the current time in the .crx Zip archive.
+ ;; Use a fixed timestamp for deterministic behavior.
+ ;; FIXME (core-updates): faketime is missing an absolute reference
+ ;; to 'date', hence the need to set PATH.
+ (setenv "PATH" #$(file-append coreutils "/bin"))
+ (invoke #$(file-append libfaketime "/bin/faketime")
+ "2000-01-01 00:00:00"
+ chromium
+ "--user-data-dir=/tmp/signing-profile"
+ (string-append "--pack-extension=" packdir)
+ (string-append "--pack-extension-key=" #$signing-key))
+ (copy-file (string-append packdir ".crx") #$output)))
+ #:local-build? #t)))
+
+(define* (crx->chromium-json crx version)
+ "Return a derivation that creates a Chromium JSON settings file for the
+extension given as CRX. VERSION is used to signify the CRX version, and
+must match the version listed in the extension manifest.json."
+ ;; See chrome/browser/extensions/external_provider_impl.cc and
+ ;; extensions/common/extension.h for documentation on the JSON format.
+ (computed-file "extension.json"
+ #~(call-with-output-file #$output
+ (lambda (port)
+ (format port "{
+ \"external_crx\": \"~a\",
+ \"external_version\": \"~a\"
+}
+"
+ #$crx #$version)))
+ #:local-build? #t))
+
+
+(define (signing-key->public-der key)
+ "Return a derivation for a file containing the public key of KEY in DER
+format."
+ (computed-file "der"
+ #~(system* #$(file-append gnutls "/bin/certtool")
+ "--load-privkey" #$key
+ "--pubkey-info"
+ "--outfile" #$output
+ "--outder")
+ #:local-build? #t))
+
+(define (chromium-json->profile-object json signing-key)
+ "Return a derivation that installs JSON to the directory searched by
+Chromium, using a file name (aka extension ID) derived from SIGNING-KEY."
+ (define der (signing-key->public-der signing-key))
+
+ (with-extensions (list guile-gcrypt)
+ (with-imported-modules '((guix build utils))
+ (computed-file
+ "chromium-extension"
+ #~(begin
+ (use-modules (guix build utils)
+ (gcrypt base16)
+ (gcrypt hash))
+ (define (base16-string->chromium-base16 str)
+ ;; Translate STR, a hexadecimal string, to a Chromium-style
+ ;; representation using the letters a-p (where a=0, p=15).
+ (define s1 "0123456789abcdef")
+ (define s2 "abcdefghijklmnop")
+ (let loop ((chars (string->list str))
+ (converted '()))
+ (if (null? chars)
+ (list->string (reverse converted))
+ (loop (cdr chars)
+ (cons (string-ref s2 (string-index s1 (car chars)))
+ converted)))))
+
+ (let* ((checksum (bytevector->base16-string (file-sha256 #$der)))
+ (file-name (base16-string->chromium-base16
+ (string-take checksum 32)))
+ (extension-directory (string-append #$output
+ "/share/chromium/extensions")))
+ (mkdir-p extension-directory)
+ (symlink #$json (string-append extension-directory "/"
+ file-name ".json"))))
+ #:local-build? #t))))
+
+(define* (make-chromium-extension p #:optional (output "out"))
+ "Create a Chromium extension from package P and return a package that,
+when installed, will make the extension contained in P available as a
+Chromium browser extension. OUTPUT specifies which output of P to use."
+ (let* ((pname (package-name p))
+ (version (package-version p))
+ (signing-key (make-signing-key pname)))
+ (package
+ (inherit p)
+ (name (string-append pname "-chromium"))
+ (source #f)
+ (build-system trivial-build-system)
+ (native-inputs '())
+ (inputs
+ `(("extension" ,(chromium-json->profile-object
+ (crx->chromium-json (make-crx signing-key p output)
+ version)
+ signing-key))))
+ (propagated-inputs '())
+ (outputs '("out"))
+ (arguments
+ '(#:modules ((guix build utils))
+ #:builder
+ (begin
+ (use-modules (guix build utils))
+ (copy-recursively (assoc-ref %build-inputs "extension")
+ (assoc-ref %outputs "out"))))))))
diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm
index 734d648575..b762e82ad2 100644
--- a/gnu/build/file-systems.scm
+++ b/gnu/build/file-systems.scm
@@ -1,9 +1,9 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016, 2017 David Craven <david@craven.ch>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2019 Guillaume Le Vaillant <glv@posteo.net>
-;;; Copyright © 2019 Tobias Geerinckx-Rice <me@tobias.gr>
+;;; Copyright © 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2019 David C. Trudgian <dave@trudgian.net>
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
@@ -181,6 +181,98 @@ if DEVICE does not contain an ext2 file system."
;;;
+;;; Linux swap.
+;;;
+
+;; Linux "swap space" is not a file system but it has a UUID and volume name,
+;; like actual file systems, and we want to be able to look up swap partitions
+;; by UUID and by label.
+
+(define %linux-swap-magic
+ (string->utf8 "SWAPSPACE2"))
+
+;; Like 'PAGE_SIZE' in Linux, arch/x86/include/asm/page.h.
+;; XXX: This is always 4K on x86_64, i386, and ARMv7. However, on AArch64,
+;; this is determined by 'CONFIG_ARM64_PAGE_SHIFT' in the kernel, which is 12
+;; by default (4K) but can be 14 or 16.
+(define %page-size 4096)
+
+(define (linux-swap-superblock? sblock)
+ "Return #t when SBLOCK is an linux-swap superblock."
+ (and (= (bytevector-length sblock) %page-size)
+ (bytevector=? (sub-bytevector sblock (- %page-size 10) 10)
+ %linux-swap-magic)))
+
+(define (read-linux-swap-superblock device)
+ "Return the raw contents of DEVICE's linux-swap superblock as a bytevector, or #f
+if DEVICE does not contain an linux-swap file system."
+ (read-superblock device 0 %page-size linux-swap-superblock?))
+
+;; See 'union swap_header' in 'include/linux/swap.h'.
+
+(define (linux-swap-superblock-uuid sblock)
+ "Return the UUID of Linux-swap superblock SBLOCK as a 16-byte bytevector."
+ (sub-bytevector sblock (+ 1024 4 4 4) 16))
+
+(define (linux-swap-superblock-volume-name sblock)
+ "Return the label of Linux-swap superblock SBLOCK as a string."
+ (null-terminated-latin1->string
+ (sub-bytevector sblock (+ 1024 4 4 4 16) 16)))
+
+
+;;;
+;;; Bcachefs file systems.
+;;;
+
+;; <https://evilpiepirate.org/git/bcachefs-tools.git/tree/libbcachefs/bcachefs_format.h>
+
+(define-syntax %bcachefs-endianness
+ ;; Endianness of bcachefs file systems.
+ (identifier-syntax (endianness little)))
+
+(define (bcachefs-superblock? sblock)
+ "Return #t when SBLOCK is an bcachefs superblock."
+ (bytevector=? (sub-bytevector sblock 24 16)
+ #vu8(#xc6 #x85 #x73 #xf6 #x4e #x1a #x45 #xca
+ #x82 #x65 #xf5 #x7f #x48 #xba #x6d #x81)))
+
+(define (read-bcachefs-superblock device)
+ "Return the raw contents of DEVICE's bcachefs superblock as a bytevector, or #f
+if DEVICE does not contain a bcachefs file system."
+ ;; We completely ignore the back-up superblock & any checksum errors.
+ ;; Superblock field names, with offset & length respectively, in bytes:
+ ;; 0 16 bch_csum
+ ;; 16 8 version
+ ;; 24 16 magic
+ ;; 40 16 uuid ← ‘internal UUID’, you probably don't want this
+ ;; 56 16 user_uuid ← ‘external UUID’, the one by which to mount
+ ;; 72 32 label
+ ;; … there are more & the superblock is extensible, but we don't care yet.
+ (read-superblock device 4096 104 bcachefs-superblock?))
+
+(define (bcachefs-superblock-external-uuid sblock)
+ "Return the external UUID of bcachefs superblock SBLOCK as a 16-byte
+bytevector."
+ (sub-bytevector sblock 56 16))
+
+(define (bcachefs-superblock-volume-name sblock)
+ "Return the volume name of SBLOCK as a string of at most 32 characters, or
+#f if SBLOCK has no volume name."
+ (null-terminated-latin1->string (sub-bytevector sblock 72 32)))
+
+(define (check-bcachefs-file-system device)
+ "Return the health of a bcachefs file system on DEVICE."
+ (match (status:exit-val
+ (apply system* "bcachefs" "fsck" "-p" "-v"
+ ;; Make each multi-device member a separate argument.
+ (string-split device #\:)))
+ (0 'pass)
+ (1 'errors-corrected)
+ (2 'reboot-required)
+ (_ 'fatal-error)))
+
+
+;;;
;;; Btrfs file systems.
;;;
@@ -596,6 +688,10 @@ partition field reader that returned a value."
iso9660-superblock-volume-name)
(partition-field-reader read-ext2-superblock
ext2-superblock-volume-name)
+ (partition-field-reader read-linux-swap-superblock
+ linux-swap-superblock-volume-name)
+ (partition-field-reader read-bcachefs-superblock
+ bcachefs-superblock-volume-name)
(partition-field-reader read-btrfs-superblock
btrfs-superblock-volume-name)
(partition-field-reader read-fat32-superblock
@@ -612,6 +708,10 @@ partition field reader that returned a value."
iso9660-superblock-uuid)
(partition-field-reader read-ext2-superblock
ext2-superblock-uuid)
+ (partition-field-reader read-linux-swap-superblock
+ linux-swap-superblock-uuid)
+ (partition-field-reader read-bcachefs-superblock
+ bcachefs-superblock-external-uuid)
(partition-field-reader read-btrfs-superblock
btrfs-superblock-uuid)
(partition-field-reader read-fat32-superblock
@@ -719,6 +819,7 @@ containing ':/')."
(define check-procedure
(cond
((string-prefix? "ext" type) check-ext2-file-system)
+ ((string-prefix? "bcachefs" type) check-bcachefs-file-system)
((string-prefix? "btrfs" type) check-btrfs-file-system)
((string-suffix? "fat" type) check-fat-file-system)
((string-prefix? "jfs" type) check-jfs-file-system)
diff --git a/gnu/build/image.scm b/gnu/build/image.scm
index ff63039c16..463b7fccc7 100644
--- a/gnu/build/image.scm
+++ b/gnu/build/image.scm
@@ -118,16 +118,16 @@ ROOT directory to populate the image."
((string=? type "vfat")
(make-vfat-image partition target root))
(else
- (format (current-error-port)
- "Unsupported partition type~%.")))))
+ (raise (condition
+ (&message
+ (message "unsupported partition type"))))))))
(define (convert-disk-image image format output)
"Convert IMAGE to OUTPUT according to the given FORMAT."
(case format
((compressed-qcow2)
- (begin
- (invoke "qemu-img" "convert" "-c" "-f" "raw"
- "-O" "qcow2" image output)))
+ (invoke "qemu-img" "convert" "-c" "-f" "raw"
+ "-O" "qcow2" image output))
(else
(copy-file image output))))
diff --git a/gnu/build/linux-boot.scm b/gnu/build/linux-boot.scm
index 32e3536039..bfaac9ec1f 100644
--- a/gnu/build/linux-boot.scm
+++ b/gnu/build/linux-boot.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016, 2017, 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2019 Guillaume Le Vaillant <glv@posteo.net>
;;;
@@ -110,6 +111,58 @@ OPTION doesn't appear in ARGUMENTS."
(substring arg (+ 1 (string-index arg #\=)))))
arguments)))
+(define (resume-if-hibernated device)
+ "Resume from hibernation if possible. This is safe ONLY if no on-disk file
+systems have been mounted; calling it later risks severe file system corruption!
+See <Documentation/swsusp.txt> in the kernel source directory. This is the
+caller's responsibility, as is catching exceptions if resumption was supposed to
+happen but didn't.
+
+Resume only from DEVICE if it's a string. If it's #f, use the kernel's default
+hibernation device (CONFIG_PM_STD_PARTITION). Never return if resumption
+succeeds. Return nothing otherwise. The kernel logs any details to dmesg."
+
+ (define (string->major:minor string)
+ "Return a string with MAJOR:MINOR numbers of the device specified by STRING"
+
+ ;; The "resume=" kernel command-line option always provides a string, which
+ ;; can represent a device, a UUID, or a label. Check for all three.
+ (let* ((spec (cond ((string-prefix? "/" string) string)
+ ((uuid string) => identity)
+ (else (file-system-label string))))
+ ;; XXX The kernel's swsusp_resume_can_resume() waits if ‘resumewait’
+ ;; is found on the command line; our canonicalize-device-spec gives
+ ;; up after 20 seconds. We could emulate the former by looping…
+ (device (canonicalize-device-spec spec))
+ (rdev (stat:rdev (stat device)))
+ ;; For backwards compatibility, device numbering is a baroque affair.
+ ;; This is the full 64-bit scheme used by glibc's <sys/sysmacros.h>.
+ (major (logior (ash (logand #x00000000000fff00 rdev) -8)
+ (ash (logand #xfffff00000000000 rdev) -32)))
+ (minor (logior (logand #x00000000000000ff rdev)
+ (ash (logand #x00000ffffff00000 rdev) -12))))
+ (format #f "~a:~a" major minor)))
+
+ ;; Write the resume DEVICE to this magic file, using the MAJOR:MINOR device
+ ;; numbers if possible. The kernel will immediately try to resume from it.
+ (let ((resume "/sys/power/resume"))
+ (when (file-exists? resume) ; this kernel supports hibernation
+ ;; Honour the kernel's default device (only) if none other was given.
+ (let ((major:minor (if device
+ (or (false-if-exception (string->major:minor
+ device))
+ ;; We can't parse it. Maybe the kernel can.
+ device)
+ (let ((default (call-with-input-file resume
+ read-line)))
+ ;; Don't waste time echoing 0:0 to /sys.
+ (if (string=? "0:0" default)
+ #f
+ default)))))
+ (when major:minor
+ (call-with-output-file resume ; may throw an ‘Invalid argument’
+ (cut display major:minor <>))))))) ; may never return
+
(define* (make-disk-device-nodes base major #:optional (minor 0))
"Make the block device nodes around BASE (something like \"/root/dev/sda\")
with the given MAJOR number, starting with MINOR."
@@ -507,6 +560,12 @@ upon error."
(load-linux-modules-from-directory linux-modules
linux-module-directory)
+ (unless (member "noresume" args)
+ ;; Try to resume immediately after loading (storage) modules
+ ;; but before any on-disk file systems have been mounted.
+ (false-if-exception ; failure is not fatal
+ (resume-if-hibernated (find-long-option "resume" args))))
+
(when keymap-file
(let ((status (system* "loadkeys" keymap-file)))
(unless (zero? status)
diff --git a/gnu/build/linux-initrd.scm b/gnu/build/linux-initrd.scm
index ea7de58553..99796adba6 100644
--- a/gnu/build/linux-initrd.scm
+++ b/gnu/build/linux-initrd.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2018, 2020 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -39,8 +39,9 @@
#:key
(compress? #t)
(gzip "gzip"))
- "Write a cpio archive containing DIRECTORY to file OUTPUT. When
-COMPRESS? is true, compress it using GZIP. On success, return OUTPUT."
+ "Write a cpio archive containing DIRECTORY to file OUTPUT, with reset
+timestamps in the archive. When COMPRESS? is true, compress it using GZIP.
+On success, return OUTPUT."
;; Note: as per `ramfs-rootfs-initramfs.txt', always add directory entries
;; before the files that are inside of it: "The Linux kernel cpio
@@ -141,12 +142,6 @@ REFERENCES-GRAPHS."
(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 "." #:gzip gzip))
;; Make sure directories are writable so we can delete files.
diff --git a/gnu/build/shepherd.scm b/gnu/build/shepherd.scm
index 91646288d5..d7b858dea4 100644
--- a/gnu/build/shepherd.scm
+++ b/gnu/build/shepherd.scm
@@ -21,7 +21,6 @@
#:use-module (gnu system file-systems)
#:use-module (gnu build linux-container)
#:use-module (guix build utils)
- #:use-module (guix utils)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
#:use-module (ice-9 match)
@@ -199,11 +198,24 @@ namespace, in addition to essential bind-mounts such /proc."
"This is a variant of 'fork+exec-command' procedure, that joins the
namespaces of process PID beforehand. If there is no support for containers,
on Hurd systems for instance, fallback to direct forking."
+ (define (strip-pid args)
+ ;; TODO: Replace with 'strip-keyword-arguments' when that no longer pulls
+ ;; in (guix config).
+ (let loop ((args args)
+ (result '()))
+ (match args
+ (()
+ (reverse result))
+ ((#:pid _ . rest)
+ (loop rest result))
+ ((head . rest)
+ (loop rest (cons head result))))))
+
(let ((container-support?
(file-exists? "/proc/self/ns"))
(fork-proc (lambda ()
(apply fork+exec-command command
- (strip-keyword-arguments '(#:pid) args)))))
+ (strip-pid args)))))
(if container-support?
(container-excursion* pid fork-proc)
(fork-proc))))