aboutsummaryrefslogtreecommitdiff
path: root/config-daemon.ac
blob: 86306effe1f8444ea7669a0249ae826fe7dd9bcf (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
dnl -*- Autoconf -*- fragment for the C++ daemon.

AC_MSG_CHECKING([whether to build daemon])
AC_MSG_RESULT([$guix_build_daemon])

dnl C++ environment.  This macro must be used unconditionnaly.
AC_PROG_CXX
AM_PROG_AR
AC_LANG([C++])

if test "x$guix_build_daemon" = "xyes"; then

  GUIX_ASSERT_CXX11

  AC_PROG_RANLIB
  AC_CONFIG_HEADERS([nix/config.h])

  dnl Use 64-bit file system calls so that we can support files > 2 GiB.
  AC_SYS_LARGEFILE

  dnl Look for zlib, a required dependency.
  AC_CHECK_LIB([z], [gzdopen], [true],
    [AC_MSG_ERROR([Guix requires zlib.  See http://www.zlib.net/.])])
  AC_CHECK_HEADERS([zlib.h], [true],
    [AC_MSG_ERROR([Guix requires zlib.  See http://www.zlib.net/.])])

  dnl Look for libbz2, an optional dependency.
  AC_CHECK_LIB([bz2], [BZ2_bzWriteOpen], [HAVE_LIBBZ2=yes], [HAVE_LIBBZ2=no])
  if test "x$HAVE_LIBBZ2" = xyes; then
    AC_CHECK_HEADERS([bzlib.h])
    HAVE_LIBBZ2="$ac_cv_header_bzlib_h"
  fi

  dnl Look for SQLite, a required dependency.
  PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19])

  AC_DEFINE_UNQUOTED([SYSTEM], ["$guix_system"],
    [Guix host system type--i.e., platform and OS kernel tuple.])

  case "$LIBGCRYPT_PREFIX" in
    no)
      LIBGCRYPT_CFLAGS=""
      ;;
    *)
      LIBGCRYPT_CFLAGS="-I$LIBGCRYPT_PREFIX/include"
      ;;
  esac

  case "$LIBGCRYPT_LIBDIR" in
    no | "")
      LIBGCRYPT_LIBS="-lgcrypt"
      ;;
    *)
      LIBGCRYPT_LIBS="-L$LIBGCRYPT_LIBDIR -lgcrypt"
      ;;
  esac

  AC_SUBST([LIBGCRYPT_CFLAGS])
  AC_SUBST([LIBGCRYPT_LIBS])

  save_CFLAGS="$CFLAGS"
  save_LDFLAGS="$LDFLAGS"
  CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
  LDFLAGS="$LDFLAGS $LIBGCRYPT_LDFLAGS"

  have_gcrypt=yes
  AC_CHECK_LIB([gcrypt], [gcry_md_open], [:], [have_gcrypt=no])
  AC_CHECK_HEADER([gcrypt.h], [:], [have_gcrypt=no])
  if test "x$have_gcrypt" != "xyes"; then
    AC_MSG_ERROR([GNU libgcrypt not found; please install it.])
  fi

  CFLAGS="$save_CFLAGS"
  LDFLAGS="$save_LDFLAGS"

  dnl Chroot support.
  AC_CHECK_FUNCS([chroot unshare])
  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])

  if test "x$ac_cv_func_chroot" != "xyes"; then
    AC_MSG_ERROR(['chroot' function missing, bailing out])
  fi

  dnl lutimes and lchown: used when canonicalizing store items.
  dnl posix_fallocate: used when extracting archives.
  dnl vfork: to speed up spawning of helper programs.
  dnl   `--> now disabled because of unpredictable behavior:
  dnl        see <http://lists.gnu.org/archive/html/guix-devel/2014-05/msg00036.html>
  dnl        and Nix commit f794465c (Nov. 2012).
  dnl sched_setaffinity: to improve RPC locality.
  dnl statvfs: to detect disk-full conditions.
  dnl strsignal: for error reporting.
  dnl statx: fine-grain 'stat' call, new in glibc 2.28.
  AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
     statvfs nanosleep strsignal statx])

  dnl Check for <locale>.
  AC_LANG_PUSH(C++)
  AC_CHECK_HEADERS([locale])
  AC_LANG_POP(C++)


  dnl Check whether we have the `personality' syscall, which allows us
  dnl to do i686-linux builds on x86_64-linux machines.
  AC_CHECK_HEADERS([sys/personality.h])

  dnl Determine the appropriate default list of substitute URLs (GnuTLS
  dnl is required so we can default to 'https'.)
  guix_substitute_urls="https://ci.guix.gnu.org https://bordeaux.guix.gnu.org"

  AC_MSG_CHECKING([for default substitute URLs])
  AC_MSG_RESULT([$guix_substitute_urls])

  AC_DEFINE_UNQUOTED([GUIX_SUBSTITUTE_URLS], ["$guix_substitute_urls"],
    [Default list of substitute URLs used by 'guix-daemon'.])

  dnl Check for Guile-SSH, which is required by 'guix offload'.
  GUIX_CHECK_GUILE_SSH

  case "x$guix_cv_have_recent_guile_ssh" in
    xyes)
      guix_build_daemon_offload="yes"
      AC_DEFINE([HAVE_DAEMON_OFFLOAD_HOOK], [1],
	[Define if the daemon's 'offload' build hook is being built (requires Guile-SSH).])
      ;;
    *)
      guix_build_daemon_offload="no"
      ;;
  esac

  dnl Temporary directory used to store the daemon's data.
  GUIX_TEST_ROOT_DIRECTORY
  GUIX_TEST_ROOT="$ac_cv_guix_test_root"
  AC_SUBST([GUIX_TEST_ROOT])

  GUIX_CHECK_LOCALSTATEDIR
fi

AM_CONDITIONAL([HAVE_LIBBZ2], [test "x$HAVE_LIBBZ2" = "xyes"])
AM_CONDITIONAL([BUILD_DAEMON], [test "x$guix_build_daemon" = "xyes"])
AM_CONDITIONAL([BUILD_DAEMON_OFFLOAD],			\
  [test "x$guix_build_daemon" = "xyes"			\
   && test "x$guix_build_daemon_offload" = "xyes"])
'#n280'>280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Christopher Allan Webber <cwebber@dustycloud.org>
;;; Copyright © 2016, 2017 Leo Famulari <leo@famulari.name>
;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com>
;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2020 Mathieu Othacehe <m.othacehe@gmail.com>
;;;
;;; 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 image)
  #:use-module (guix build store-copy)
  #:use-module (guix build syscalls)
  #:use-module (guix build utils)
  #:use-module (guix store database)
  #:use-module (gnu build bootloader)
  #:use-module (gnu build install)
  #:use-module (gnu build linux-boot)
  #:use-module (gnu image)
  #:use-module (gnu system uuid)
  #:use-module (ice-9 ftw)
  #:use-module (ice-9 match)
  #:use-module (srfi srfi-19)
  #:use-module (srfi srfi-34)
  #:use-module (srfi srfi-35)
  #:export (make-partition-image
            convert-disk-image
            genimage
            initialize-efi-partition
            initialize-root-partition

            make-iso9660-image))

(define (sexp->partition sexp)
  "Take SEXP, a tuple as returned by 'partition->gexp', and turn it into a
<partition> record."
  (match sexp
    ((size file-system file-system-options label uuid)
     (partition (size size)
                (file-system file-system)
                (file-system-options file-system-options)
                (label label)
                (uuid uuid)))))

(define (size-in-kib size)
  "Convert SIZE expressed in bytes, to kilobytes and return it as a string."
  (number->string
   (inexact->exact (ceiling (/ size 1024)))))

(define (estimate-partition-size root)
  "Given the ROOT directory, evaluate and return its size.  As this doesn't
take the partition metadata size into account, take a 25% margin."
  (* 1.25 (file-size root)))

(define* (make-ext-image partition target root
                         #:key
                         (owner-uid 0)
                         (owner-gid 0))
  "Handle the creation of EXT2/3/4 partition images. See
'make-partition-image'."
  (let ((size (partition-size partition))
        (fs (partition-file-system partition))
        (fs-options (partition-file-system-options partition))
        (label (partition-label partition))
        (uuid (partition-uuid partition))
        (journal-options "lazy_itable_init=1,lazy_journal_init=1"))
    (apply invoke
           `("fakeroot" "mke2fs" "-t" ,fs "-d" ,root
             "-L" ,label "-U" ,(uuid->string uuid)
             "-E" ,(format #f "root_owner=~a:~a,~a"
                           owner-uid owner-gid journal-options)
             ,@fs-options
             ,target
             ,(format #f "~ak"
                      (size-in-kib
                       (if (eq? size 'guess)
                           (estimate-partition-size root)
                           size)))))))

(define* (make-vfat-image partition target root)
  "Handle the creation of VFAT partition images.  See 'make-partition-image'."
  (let ((size (partition-size partition))
        (label (partition-label partition)))
    (invoke "fakeroot" "mkdosfs" "-n" label "-C" target
            "-F" "16" "-S" "1024"
            (size-in-kib
             (if (eq? size 'guess)
                 (estimate-partition-size root)
                 size)))
    (for-each (lambda (file)
                (unless (member file '("." ".."))
                  (invoke "mcopy" "-bsp" "-i" target
                          (string-append root "/" file)
                          (string-append "::" file))))
              (scandir root))))

(define* (make-partition-image partition-sexp target root)
  "Create and return the image of PARTITION-SEXP as TARGET.  Use the given
ROOT directory to populate the image."
  (let* ((partition (sexp->partition partition-sexp))
         (type (partition-file-system partition)))
    (cond
     ((string-prefix? "ext" type)
      (make-ext-image partition target root))
     ((string=? type "vfat")
      (make-vfat-image partition target root))
     (else
      (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)
     (invoke "qemu-img" "convert" "-c" "-f" "raw"
             "-O" "qcow2" image output))
    (else
     (copy-file image output))))

(define* (genimage config)
  "Use genimage to generate in TARGET directory, the image described in the
given CONFIG file."
  ;; genimage needs a 'root' directory.
  (mkdir "root")
  (invoke "genimage" "--config" config))

(define* (register-closure prefix closure
                           #:key
                           (schema (sql-schema))
                           (wal-mode? #t))
  "Register CLOSURE in PREFIX, where PREFIX is the directory name of the
target store and CLOSURE is the name of a file containing a reference graph as
produced by #:references-graphs.  Pass WAL-MODE? to call-with-database."
  (let ((items (call-with-input-file closure read-reference-graph)))
    (parameterize ((sql-schema schema))
      (with-database (store-database-file #:prefix prefix) db
       #:wal-mode? wal-mode?
       (register-items db items
                       #:prefix prefix
                       #:registration-time %epoch)))))

(define* (initialize-efi-partition root
                                   #:key
                                   grub-efi
                                   #:allow-other-keys)
  "Install in ROOT directory, an EFI loader using GRUB-EFI."
  (install-efi-loader grub-efi root))

(define* (initialize-root-partition root
                                    #:key
                                    bootcfg
                                    bootcfg-location
                                    bootloader-package
                                    bootloader-installer
                                    (deduplicate? #t)
                                    references-graphs
                                    (register-closures? #t)
                                    system-directory
                                    make-device-nodes
                                    (wal-mode? #t)
                                    #:allow-other-keys)
  "Initialize the given ROOT directory. Use BOOTCFG and BOOTCFG-LOCATION to
install the bootloader configuration.

If REGISTER-CLOSURES? is true, register REFERENCES-GRAPHS in the store.  If
DEDUPLICATE? is true, then also deduplicate files common to CLOSURES and the
rest of the store when registering the closures.  SYSTEM-DIRECTORY is the name
of the directory of the 'system' derivation.  Pass WAL-MODE? to
register-closure."
  (populate-root-file-system system-directory root)
  (populate-store references-graphs root
                  #:deduplicate? deduplicate?)

  ;; Populate /dev.
  (when make-device-nodes
    (make-device-nodes root))

  (when register-closures?
    (for-each (lambda (closure)
                (register-closure root closure
                                  #:wal-mode? wal-mode?))
              references-graphs))

  (when bootloader-installer
    (display "installing bootloader...\n")
    (bootloader-installer bootloader-package #f root))
  (when bootcfg
    (install-boot-config bootcfg bootcfg-location root)))

(define* (make-iso9660-image xorriso grub-mkrescue-environment
                             grub bootcfg system-directory root target
                             #:key (volume-id "Guix_image") (volume-uuid #f)
                             register-closures? (references-graphs '())
                             (compression? #t))
  "Given a GRUB package, creates an iso image as TARGET, using BOOTCFG as
GRUB configuration and OS-DRV as the stuff in it."
  (define grub-mkrescue
    (string-append grub "/bin/grub-mkrescue"))

  (define grub-mkrescue-sed.sh
    (string-append (getcwd) "/" "grub-mkrescue-sed.sh"))

  ;; Use a modified version of grub-mkrescue-sed.sh, see below.
  (copy-file (string-append xorriso
                            "/bin/grub-mkrescue-sed.sh")
             grub-mkrescue-sed.sh)

  ;; Force grub-mkrescue-sed.sh to use the build directory instead of /tmp
  ;; that is read-only inside the build container.
  (substitute* grub-mkrescue-sed.sh
    (("/tmp/") (string-append (getcwd) "/"))
    (("MKRESCUE_SED_XORRISO_ARGS \\$x")
     (format #f "MKRESCUE_SED_XORRISO_ARGS $(echo $x | sed \"s|/tmp|~a|\")"
             (getcwd))))

  ;; 'grub-mkrescue' calls out to mtools programs to create 'efi.img', a FAT
  ;; file system image, and mtools honors SOURCE_DATE_EPOCH for the mtime of
  ;; those files.  The epoch for FAT is Jan. 1st 1980, not 1970, so choose
  ;; that.
  (setenv "SOURCE_DATE_EPOCH"
          (number->string
           (time-second
            (date->time-utc (make-date 0 0 0 0 1 1 1980 0)))))

  ;; Our patched 'grub-mkrescue' honors this environment variable and passes
  ;; it to 'mformat', which makes it the serial number of 'efi.img'.  This
  ;; allows for deterministic builds.
  (setenv "GRUB_FAT_SERIAL_NUMBER"
          (number->string (if volume-uuid

                              ;; On 32-bit systems the 2nd argument must be
                              ;; lower than 2^32.
                              (string-hash (iso9660-uuid->string volume-uuid)
                                           (- (expt 2 32) 1))

                              #x77777777)
                          16))

  (setenv "MKRESCUE_SED_MODE" "original")
  (setenv "MKRESCUE_SED_XORRISO" (string-append xorriso "/bin/xorriso"))
  (setenv "MKRESCUE_SED_IN_EFI_NO_PT" "yes")

  (for-each (match-lambda
              ((name . value) (setenv name value)))
            grub-mkrescue-environment)

  (apply invoke grub-mkrescue
         (string-append "--xorriso=" grub-mkrescue-sed.sh)
         "-o" target
         (string-append "boot/grub/grub.cfg=" bootcfg)
         root
         "--"
         ;; Set all timestamps to 1.
         "-volume_date" "all_file_dates" "=1"

         `(,@(if compression?
                 '(;; ‘zisofs’ compression reduces the total image size by
                   ;; ~60%.
                   "-zisofs" "level=9:block_size=128k" ; highest compression
                   ;; It's transparent to our Linux-Libre kernel but not to
                   ;; GRUB.  Don't compress the kernel, initrd, and other
                   ;; files read by grub.cfg, as well as common
                   ;; already-compressed file names.
                   "-find" "/" "-type" "f"
                   ;; XXX Even after "--" above, and despite documentation
                   ;; claiming otherwise, "-or" is stolen by grub-mkrescue
                   ;; which then chokes on it (as ‘-o …’) and dies.  Don't use
                   ;; "-or".
                   "-not" "-wholename" "/boot/*"
                   "-not" "-wholename" "/System/*"
                   "-not" "-name" "unicode.pf2"
                   "-not" "-name" "bzImage"
                   "-not" "-name" "*.gz"   ; initrd & all man pages
                   "-not" "-name" "*.png"  ; includes grub-image.png
                   "-exec" "set_filter" "--zisofs"
                   "--")
                 '())
           "-volid" ,(string-upcase volume-id)
           ,@(if volume-uuid
             `("-volume_date" "uuid"
               ,(string-filter (lambda (value)
                                 (not (char=? #\- value)))
                               (iso9660-uuid->string
                                volume-uuid)))
             '()))))