system: Add 'ping6' to %SETUID-PROGRAMS.
[jackhill/guix/guix.git] / gnu / system.scm
index ece61ad..284dbe2 100644 (file)
@@ -1,5 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2015 Alex Kost <alezost@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -24,6 +26,7 @@
   #:use-module (guix packages)
   #:use-module (guix derivations)
   #:use-module (guix profiles)
+  #:use-module (guix ui)
   #:use-module (gnu packages base)
   #:use-module (gnu packages bash)
   #:use-module (gnu packages guile)
@@ -65,6 +68,7 @@
             operating-system-host-name
             operating-system-hosts-file
             operating-system-kernel
+            operating-system-kernel-arguments
             operating-system-initrd
             operating-system-users
             operating-system-groups
   make-operating-system
   operating-system?
   (kernel operating-system-kernel                 ; package
-          (default linux-libre))
+          (default linux-libre-4.0))
+  (kernel-arguments operating-system-kernel-arguments
+                    (default '()))                ; list of gexps/strings
   (bootloader operating-system-bootloader)        ; <grub-configuration>
 
   (initrd operating-system-initrd                 ; (list fs) -> M derivation
             (default %base-firmware))
 
   (host-name operating-system-host-name)          ; string
-  (hosts-file operating-system-hosts-file         ; M item | #f
+  (hosts-file operating-system-hosts-file         ; file-like | #f
               (default #f))
 
   (mapped-devices operating-system-mapped-devices ; list of <mapped-device>
                 (default '()))
 
   (users operating-system-users                   ; list of user accounts
-         (default '()))
+         (default %base-user-accounts))
   (groups operating-system-groups                 ; list of user groups
           (default %base-groups))
 
   (setuid-programs operating-system-setuid-programs
                    (default %setuid-programs))    ; list of string-valued gexps
 
-  (sudoers operating-system-sudoers               ; /etc/sudoers contents
-           (default %sudoers-specification)))
+  (sudoers-file operating-system-sudoers-file     ; file-like
+                (default %sudoers-specification)))
 
 \f
 ;;;
@@ -222,10 +228,16 @@ as 'needed-for-boot'."
             (operating-system-mapped-devices os)))
 
   (define (requirements fs)
-    (map (lambda (md)
-           (symbol-append 'device-mapping-
-                          (string->symbol (mapped-device-target md))))
-         (device-mappings fs)))
+    ;; XXX: Fiddling with dmd service names is not nice.
+    (append (map (lambda (fs)
+                   (symbol-append 'file-system-
+                                  (string->symbol
+                                   (file-system-mount-point fs))))
+                 (file-system-dependencies fs))
+            (map (lambda (md)
+                   (symbol-append 'device-mapping-
+                                  (string->symbol (mapped-device-target md))))
+                 (device-mappings fs))))
 
   (sequence %store-monad
             (map (lambda (fs)
@@ -372,7 +384,7 @@ This is the GNU system.  Welcome.\n")
 
 (define (default-/etc/hosts host-name)
   "Return the default /etc/hosts file."
-  (text-file "hosts" (local-host-aliases host-name)))
+  (plain-file "hosts" (local-host-aliases host-name)))
 
 (define (emacs-site-file)
   "Return the Emacs 'site-start.el' file.  That file contains the necessary
@@ -388,12 +400,8 @@ settings for 'guix.el' to work out-of-the-box."
                  ;; Attempt to load guix.el.
                  (require 'guix-init nil t)
 
-                 (when (require 'geiser-guile nil t)
-                   ;; Make sure Geiser's Scheme modules are in Guile's search
-                   ;; path.
-                   (add-to-list
-                    'geiser-guile-load-path
-                    "/run/current-system/profile/share/geiser/guile")))))
+                 ;; Attempt to load geiser.
+                 (require 'geiser-install nil t))))
 
 (define (emacs-site-directory)
   "Return the Emacs site directory, aka. /etc/emacs."
@@ -404,30 +412,46 @@ settings for 'guix.el' to work out-of-the-box."
                           (chdir #$output)
                           (symlink #$file "site-start.el")))))
 
+(define (user-shells os)
+  "Return the list of all the shells used by the accounts of OS.  These may be
+gexps or strings."
+  (mlet %store-monad ((accounts (operating-system-accounts os)))
+    (return (map user-account-shell accounts))))
+
+(define (shells-file shells)
+  "Return a derivation that builds a shell list for use as /etc/shells based
+on SHELLS.  /etc/shells is used by xterm, polkit, and other programs."
+  (gexp->derivation "shells"
+                    #~(begin
+                        (use-modules (srfi srfi-1))
+
+                        (define shells
+                          (delete-duplicates (list #$@shells)))
+
+                        (call-with-output-file #$output
+                          (lambda (port)
+                            (display "\
+/bin/sh
+/run/current-system/profile/bin/sh
+/run/current-system/profile/bin/bash\n" port)
+                            (for-each (lambda (shell)
+                                        (display shell port)
+                                        (newline port))
+                                      shells))))))
+
 (define* (etc-directory #:key
                         (locale "C") (timezone "Europe/Paris")
                         (issue "Hello!\n")
                         (skeletons '())
                         (pam-services '())
                         (profile "/run/current-system/profile")
-                        hosts-file nss
-                        (sudoers ""))
+                        hosts-file nss (shells '())
+                        (sudoers-file (plain-file "sudoers" "")))
   "Return a derivation that builds the static part of the /etc directory."
   (mlet* %store-monad
       ((pam.d      (pam-services->directory pam-services))
-       (sudoers    (text-file "sudoers" sudoers))
        (login.defs (text-file "login.defs" "# Empty for now.\n"))
-
-       ;; /etc/shells is used by xterm and other programs.   We don't check
-       ;; whether these shells are installed, should be OK.
-       (shells     (text-file "shells"
-                              "\
-/bin/sh
-/run/current-system/profile/bin/sh
-/run/current-system/profile/bin/bash
-/run/current-system/profile/bin/fish
-/run/current-system/profile/bin/tcsh
-/run/current-system/profile/bin/zsh\n"))
+       (shells     (shells-file shells))
        (emacs      (emacs-site-directory))
        (issue      (text-file "issue" issue))
        (nsswitch   (text-file "nsswitch.conf"
@@ -443,14 +467,40 @@ export TZDIR=\"" tzdata "/share/zoneinfo\"
 # Tell 'modprobe' & co. where to look for modules.
 export LINUX_MODULE_DIRECTORY=/run/booted-system/kernel/lib/modules
 
-export PATH=$HOME/.guix-profile/bin:/run/current-system/profile/bin
-export PATH=/run/setuid-programs:/run/current-system/profile/sbin:$PATH
+# These variables are honored by OpenSSL (libssl) and Git.
+export SSL_CERT_DIR=/etc/ssl/certs
+export SSL_CERT_FILE=\"$SSL_CERT_DIR/ca-certificates.crt\"
+export GIT_SSL_CAINFO=\"$SSL_CERT_FILE\"
+
+# Crucial variables that could be missing in the profiles' 'etc/profile'
+# because they would require combining both profiles.
+# FIXME: See <http://bugs.gnu.org/20255>.
 export MANPATH=$HOME/.guix-profile/share/man:/run/current-system/profile/share/man
 export INFOPATH=$HOME/.guix-profile/share/info:/run/current-system/profile/share/info
-
 export XDG_DATA_DIRS=$HOME/.guix-profile/share:/run/current-system/profile/share
 export XDG_CONFIG_DIRS=$HOME/.guix-profile/etc/xdg:/run/current-system/profile/etc/xdg
 
+# Ignore the default value of 'PATH'.
+unset PATH
+
+# Load the system profile's settings.
+GUIX_PROFILE=/run/current-system/profile \\
+. /run/current-system/profile/etc/profile
+
+# Prepend setuid programs.
+export PATH=/run/setuid-programs:$PATH
+
+if [ -f \"$HOME/.guix-profile/etc/profile\" ]
+then
+  # Load the user profile's settings.
+  GUIX_PROFILE=\"$HOME/.guix-profile\" \\
+  . \"$HOME/.guix-profile/etc/profile\"
+else
+  # At least define this one so that basic things just work
+  # when the user installs their first package.
+  export PATH=\"$HOME/.guix-profile/bin:$PATH\"
+fi
+
 # Append the directory of 'site-start.el' to the search path.
 export EMACSLOADPATH=:/etc/emacs
 
@@ -458,18 +508,13 @@ export EMACSLOADPATH=:/etc/emacs
 # when /etc/machine-id is missing.  Make sure these warnings are non-fatal.
 export DBUS_FATAL_WARNINGS=0
 
-# These variables are honored by OpenSSL (libssl) and Git.
-export SSL_CERT_DIR=/etc/ssl/certs
-export SSL_CERT_FILE=\"$SSL_CERT_DIR/ca-certificates.crt\"
-export GIT_SSL_CAINFO=\"$SSL_CERT_FILE\"
-
 # Allow Aspell to find dictionaries installed in the user profile.
 export ASPELL_CONF=\"dict-dir $HOME/.guix-profile/lib/aspell\"
 
 if [ -n \"$BASH_VERSION\" -a -f /etc/bashrc ]
 then
   # Load Bash-specific initialization code.
-  source /etc/bashrc
+  . /etc/bashrc
 fi
 "))
 
@@ -501,7 +546,7 @@ fi\n"))
                   ("hosts" ,#~#$hosts-file)
                   ("localtime" ,#~(string-append #$tzdata "/share/zoneinfo/"
                                                  #$timezone))
-                  ("sudoers" ,#~#$sudoers)))))
+                  ("sudoers" ,sudoers-file)))))
 
 (define (operating-system-profile os)
   "Return a derivation that builds the system profile of OS."
@@ -531,6 +576,37 @@ fi\n"))
     (return (append users
                     (append-map service-user-accounts services)))))
 
+(define (maybe-string->file file-name thing)
+  "If THING is a string, return a <plain-file> with THING as its content.
+Otherwise just return THING.
+
+This is for backward-compatibility of fields that used to be strings and are
+now file-like objects.."
+  (match thing
+    ((? string?)
+     (warning (_ "using a string for file '~a' is deprecated; \
+use 'plain-file' instead~%")
+              file-name)
+     (plain-file file-name thing))
+    (x
+     x)))
+
+(define (maybe-file->monadic file-name thing)
+  "If THING is a value in %STORE-MONAD, return it as is; otherwise return
+THING in the %STORE-MONAD.
+
+This is for backward-compatibility of fields that used to be monadic values
+and are now file-like objects."
+  (with-monad %store-monad
+    (match thing
+      ((? procedure?)
+       (warning (_ "using a monadic value for '~a' is deprecated; \
+use 'plain-file' instead~%")
+                file-name)
+       thing)
+      (x
+       (return x)))))
+
 (define (operating-system-etc-directory os)
   "Return that static part of the /etc directory of OS."
   (mlet* %store-monad
@@ -541,8 +617,11 @@ fi\n"))
                              (append-map service-pam-services services)))
        (profile-drv (operating-system-profile os))
        (skeletons   (operating-system-skeletons os))
-       (/etc/hosts  (or (operating-system-hosts-file os)
-                        (default-/etc/hosts (operating-system-host-name os)))))
+       (/etc/hosts  (maybe-file->monadic
+                     "hosts"
+                     (or (operating-system-hosts-file os)
+                         (default-/etc/hosts (operating-system-host-name os)))))
+       (shells      (user-shells os)))
    (etc-directory #:pam-services pam-services
                   #:skeletons skeletons
                   #:issue (operating-system-issue os)
@@ -550,7 +629,10 @@ fi\n"))
                   #:nss (operating-system-name-service-switch os)
                   #:timezone (operating-system-timezone os)
                   #:hosts-file /etc/hosts
-                  #:sudoers (operating-system-sudoers os)
+                  #:shells shells
+                  #:sudoers-file (maybe-string->file
+                                  "sudoers"
+                                  (operating-system-sudoers-file os))
                   #:profile profile-drv)))
 
 (define %setuid-programs
@@ -559,6 +641,7 @@ fi\n"))
     (list #~(string-append #$shadow "/bin/passwd")
           #~(string-append #$shadow "/bin/su")
           #~(string-append #$inetutils "/bin/ping")
+          #~(string-append #$inetutils "/bin/ping6")
           #~(string-append #$sudo "/bin/sudo")
           #~(string-append #$fuse "/bin/fusermount"))))
 
@@ -567,8 +650,9 @@ fi\n"))
   ;; group can do anything.  See
   ;; <http://www.sudo.ws/sudo/man/1.8.10/sudoers.man.html>.
   ;; TODO: Add a declarative API.
-  "root ALL=(ALL) ALL
-%wheel ALL=(ALL) ALL\n")
+  (plain-file "sudoers" "\
+root ALL=(ALL) ALL
+%wheel ALL=(ALL) ALL\n"))
 
 (define (user-group->gexp group)
   "Turn GROUP, a <user-group> object, into a list-valued gexp suitable for
@@ -615,6 +699,7 @@ etc."
       (gnu build linux-modules)
       (gnu build file-systems)
       (guix build utils)
+      (guix build syscalls)
       (guix elf)))
 
   (define (service-activations services)
@@ -645,6 +730,8 @@ etc."
     (define group-specs
       (map user-group->gexp groups))
 
+    (assert-valid-users/groups accounts groups)
+
     (gexp->file "activate"
                 #~(begin
                     (eval-when (expand load eval)
@@ -680,6 +767,9 @@ etc."
                     (activate-firmware
                      (string-append #$firmware "/lib/firmware"))
 
+                    ;; Let users debug their own processes!
+                    (activate-ptrace-attach)
+
                     ;; Run the services' activation snippets.
                     ;; TODO: Use 'load-compiled'.
                     (for-each primitive-load '#$actions)
@@ -695,6 +785,20 @@ we're running in the final root."
                        (dmd-conf (dmd-configuration-file services)))
     (gexp->file "boot"
                 #~(begin
+                    (use-modules (guix build utils))
+
+                    ;; Clean out /tmp and /var/run.
+                    ;;
+                    ;; XXX This needs to happen before service activations, so
+                    ;; it has to be here, but this also implicitly assumes
+                    ;; that /tmp and /var/run are on the root partition.
+                    (false-if-exception (delete-file-recursively "/tmp"))
+                    (false-if-exception (delete-file-recursively "/var/run"))
+                    (false-if-exception (mkdir "/tmp"))
+                    (false-if-exception (chmod "/tmp" #o1777))
+                    (false-if-exception (mkdir "/var/run"))
+                    (false-if-exception (chmod "/var/run" #o755))
+
                     ;; Activate the system.
                     ;; TODO: Use 'load-compiled'.
                     (primitive-load #$activate)
@@ -772,11 +876,12 @@ listed in OS.  The C library expects to find it under
                            (label (kernel->grub-label kernel))
                            (linux kernel)
                            (linux-arguments
-                            (list (string-append "--root="
-                                                 (file-system-device root-fs))
-                                  #~(string-append "--system=" #$system)
-                                  #~(string-append "--load=" #$system
-                                                   "/boot")))
+                            (cons* (string-append "--root="
+                                                  (file-system-device root-fs))
+                                   #~(string-append "--system=" #$system)
+                                   #~(string-append "--load=" #$system
+                                                    "/boot")
+                                   (operating-system-kernel-arguments os)))
                            (initrd #~(string-append #$system "/initrd"))))))
     (grub-configuration-file (operating-system-bootloader os) entries
                              #:old-entries old-entries)))
@@ -793,6 +898,8 @@ this file is the reconstruction of GRUB menu entries for old configurations."
                                    (label #$label)
                                    (root-device #$(file-system-device root))
                                    (kernel #$(operating-system-kernel os))
+                                   (kernel-arguments
+                                    #$(operating-system-kernel-arguments os))
                                    (initrd #$initrd)))))
 
 (define (operating-system-derivation os)