aboutsummaryrefslogtreecommitdiff
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014, 2015, 2018, 2020 Ludovic Courtès <ludo@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 linux-initrd)
  #:use-module ((guix cpio) #:prefix cpio:)
  #:use-module (guix build utils)
  #:use-module (guix build store-copy)
  #:use-module (system base compile)
  #:use-module (rnrs bytevectors)
  #:use-module ((system foreign) #:select (sizeof))
  #:use-module (ice-9 ftw)
  #:export (write-cpio-archive
            build-initrd))

;;; Commentary:
;;;
;;; Tools to create Linux initial RAM disks ("initrds").  Initrds are
;;; essentially gzipped cpio archives, with a '/init' executable that the
;;; kernel runs at boot time.
;;;
;;; Code:

(define* (write-cpio-archive output directory
                             #:key
                             (compress? #t)
                             (gzip "gzip"))
  "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
  ;; extractor won't create files in a directory that doesn't exist, so the
  ;; directory entries must go before the files that go in those
  ;; directories."

  (define files
    ;; Use 'sort' so that (1) the order of files is deterministic, and (2)
    ;; directories appear before the files they contain.
    (sort (file-system-fold (const #t)                 ;enter?
                            (lambda (file stat result) ;leaf
                              (cons file result))
                            (lambda (dir stat result)  ;down
                              (if (string=? dir directory)
                                  result
                                  (cons dir result)))
                            (lambda (file stat result)
                              result)
                            (const #f)                 ;skip
                            (const #f)                 ;error
                            '()
                            directory)
          string<?))

  (call-with-output-file output
    (lambda (port)
      (cpio:write-cpio-archive files port
                               #:file->header cpio:file->cpio-header*)))

  (if compress?
      ;; Gzip insists on adding a '.gz' suffix and does nothing if the input
      ;; file already has that suffix.  Shuffle files around to placate it.
      (let* ((gz-suffix? (string-suffix? ".gz" output))
             (sans-gz    (if gz-suffix?
                             (string-drop-right output 3)
                             output)))
        (when gz-suffix?
          (rename-file output sans-gz))
        ;; Use '--no-name' so that gzip records neither a file name nor a time
        ;; stamp in its output.
        (and (zero? (system* gzip "--best" "--no-name" sans-gz))
             (begin
               (unless gz-suffix?
                 (rename-file (string-append output ".gz") output))
               output)))
      output))

(define (cache-compiled-file-name file)
  "Return the file name of the in-cache .go file for FILE, relative to the
current directory.

This is similar to what 'compiled-file-name' in (system base compile) does."
  (let loop ((file file))
    (let ((target (false-if-exception (readlink file))))
     (if target
         (loop target)
         (format #f ".cache/guile/ccache/~a-~a-~a-~a/~a"
                 (effective-version)
                 (if (eq? (native-endianness) (endianness little))
                     "LE"
                     "BE")
                 (sizeof '*)
                 (effective-version)
                 file)))))

(define (compile-to-cache file)
  "Compile FILE to the cache."
  (let ((compiled-file (cache-compiled-file-name file)))
    (mkdir-p (dirname compiled-file))
    (compile-file file
                  #:opts %auto-compilation-options
                  #:output-file compiled-file)))

(define* (build-initrd output
                       #:key
                       guile init
                       (references-graphs '())
                       (gzip "gzip"))
  "Write an initial RAM disk (initrd) to OUTPUT.  The initrd starts the script
at INIT, running GUILE.  It contains all the items referred to by
REFERENCES-GRAPHS."
  (mkdir "contents")

  ;; Copy the closures of all the items referenced in REFERENCES-GRAPHS.
  (populate-store references-graphs "contents"
                  #:deduplicate? #f)

  (with-directory-excursion "contents"
    ;; Make '/init'.
    (symlink init "init")

    ;; Compile it.
    (compile-to-cache "init")

    ;; Allow Guile to find out where it is (XXX).  See
    ;; 'guile-relocatable.patch'.
    (mkdir-p "proc/self")
    (symlink (string-append guile "/bin/guile") "proc/self/exe")
    (readlink "proc/self/exe")

    (write-cpio-archive output "." #:gzip gzip))

  ;; Make sure directories are writable so we can delete files.
  (for-each make-file-writable
            (find-files "contents"
                        (lambda (file stat)
                          (eq? 'directory (stat:type stat)))
                        #:directories? #t))
  (delete-file-recursively "contents"))

;;; linux-initrd.scm ends here
unsafe-pattern field. (gitolite-rc-file-compiler): Write it. * doc/guix.texi (Version Control Services): Document it. Julien Lepiller 2021-04-10services: git-daemon: Fix typo in docstring....* gnu/services/version-control.scm (git-daemon-service): Fix docstring typo. Tobias Geerinckx-Rice 2020-10-05services: gitolite: Install the rc file as gitolite's user....* gnu/services/version-control.scm (gitolite-activation): Install the rc file as gitolite's user. Julien Lepiller 2020-05-13mailmap: Update entries for Nikita....* .mailmap: change email and name for Nikita. * Makefile.am, doc/guix.texi, etc/completion/fish/guix.fish, gnu/packages/accessibility.scm, gnu/packages/admin.scm, gnu/packages/audio.scm, gnu/packages/autotools.scm, gnu/packages/cdrom.scm, gnu/packages/check.scm, gnu/packages/cinnamon.scm, gnu/packages/compression.scm, gnu/packages/crypto.scm, gnu/packages/databases.scm, gnu/packages/django.scm, gnu/packages/dns.scm, gnu/packages/elixir.scm, gnu/packages/emacs-xyz.scm, gnu/packages/emacs.scm, gnu/packages/enlightenment.scm, gnu/packages/erlang.scm, gnu/packages/fonts.scm, gnu/packages/fontutils.scm, gnu/packages/forth.scm, gnu/packages/fvwm.scm, gnu/packages/games.scm, gnu/packages/gl.scm, gnu/packages/gnome.scm, gnu/packages/gnunet.scm, gnu/packages/gnupg.scm, gnu/packages/gtk.scm, gnu/packages/guile-wm.scm, gnu/packages/guile-xyz.scm, gnu/packages/haskell-apps.scm, gnu/packages/haskell-check.scm, gnu/packages/haskell-crypto.scm, gnu/packages/haskell-xyz.scm, gnu/packages/haskell.scm, gnu/packages/image-viewers.scm, gnu/packages/image.scm, gnu/packages/irc.scm, gnu/packages/language.scm, gnu/packages/libcanberra.scm, gnu/packages/linux.scm, gnu/packages/lisp-xyz.scm, gnu/packages/lisp.scm, gnu/packages/lolcode.scm, gnu/packages/lxde.scm, gnu/packages/lxqt.scm, gnu/packages/mail.scm, gnu/packages/markup.scm, gnu/packages/mate.scm, gnu/packages/maths.scm, gnu/packages/mc.scm, gnu/packages/messaging.scm, gnu/packages/music.scm, gnu/packages/ncurses.scm, gnu/packages/networking.scm, gnu/packages/nickle.scm, gnu/packages/openbox.scm, gnu/packages/pdf.scm, gnu/packages/perl-check.scm, gnu/packages/perl.scm, gnu/packages/python-compression.scm, gnu/packages/python-crypto.scm, gnu/packages/python-web.scm, gnu/packages/python-xyz.scm, gnu/packages/python.scm, gnu/packages/qt.scm, gnu/packages/ruby.scm, gnu/packages/rust.scm, gnu/packages/scheme.scm, gnu/packages/serialization.scm, gnu/packages/shells.scm, gnu/packages/ssh.scm, gnu/packages/suckless.scm, gnu/packages/tbb.scm, gnu/packages/telephony.scm, gnu/packages/text-editors.scm, gnu/packages/textutils.scm, gnu/packages/time.scm, gnu/packages/tls.scm, gnu/packages/tor.scm, gnu/packages/version-control.scm, gnu/packages/video.scm, gnu/packages/vim.scm, gnu/packages/web.scm, gnu/packages/wm.scm, gnu/packages/xdisorg.scm, gnu/packages/xfce.scm, gnu/packages/xml.scm, gnu/packages/xorg.scm, gnu/services/certbot.scm, gnu/services/desktop.scm, gnu/services/version-control.scm, gnu/services/web.scm, guix/import/hackage.scm, guix/licenses.scm: Likewise. Signed-off-by: Efraim Flashner <efraim@flashner.co.il> nikita