summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
Diffstat (limited to 'guix')
-rw-r--r--guix/build/download.scm18
-rw-r--r--guix/build/syscalls.scm163
-rw-r--r--guix/profiles.scm8
-rw-r--r--guix/scripts/offload.scm43
-rw-r--r--guix/scripts/package.scm15
-rw-r--r--guix/scripts/pull.scm86
-rw-r--r--guix/ui.scm13
-rw-r--r--guix/utils.scm5
8 files changed, 267 insertions, 84 deletions
diff --git a/guix/build/download.scm b/guix/build/download.scm
index d98933a907..c081f3b29b 100644
--- a/guix/build/download.scm
+++ b/guix/build/download.scm
@@ -112,13 +112,25 @@ abbreviation of URI showing the scheme, host, and basename of the file."
"Hold a weak reference from FROM to TO."
(hashq-set! table from to))))
-(define (tls-wrap port)
- "Return PORT wrapped in a TLS connection."
+(define (tls-wrap port server)
+ "Return PORT wrapped in a TLS connection to SERVER. SERVER must be a DNS
+host name without trailing dot."
(define (log level str)
(format (current-error-port)
"gnutls: [~a|~a] ~a" (getpid) level str))
(let ((session (make-session connection-end/client)))
+
+ ;; Some servers such as 'cloud.github.com' require the client to support
+ ;; the 'SERVER NAME' extension. However, 'set-session-server-name!' is
+ ;; not available in older GnuTLS releases. See
+ ;; <http://bugs.gnu.org/18526> for details.
+ (if (module-defined? (resolve-interface '(gnutls))
+ 'set-session-server-name!)
+ (set-session-server-name! session server-name-type/dns server)
+ (format (current-error-port)
+ "warning: TLS 'SERVER NAME' extension not supported~%"))
+
(set-session-transport-fd! session (fileno port))
(set-session-default-priority! session)
(set-session-credentials! session (make-certificate-credentials))
@@ -169,7 +181,7 @@ which is not available during bootstrap."
(setvbuf s _IOFBF)
(if (eq? 'https (uri-scheme uri))
- (tls-wrap s)
+ (tls-wrap s (uri-host uri))
s))
(lambda args
;; Connection failed, so try one of the other addresses.
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 7a1bad7331..7e5245fcc6 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -21,6 +21,7 @@
#:use-module (rnrs bytevectors)
#:use-module (srfi srfi-1)
#:use-module (ice-9 rdelim)
+ #:use-module (ice-9 regex)
#:use-module (ice-9 match)
#:use-module (ice-9 ftw)
#:export (errno
@@ -30,7 +31,17 @@
MS_MOVE
mount
umount
- processes))
+ swapon
+ swapoff
+ processes
+
+ IFF_UP
+ IFF_BROADCAST
+ IFF_LOOPBACK
+ all-network-interfaces
+ network-interfaces
+ network-interface-flags
+ loopback-network-interface?))
;;; Commentary:
;;;
@@ -155,6 +166,30 @@ constants from <sys/mount.h>."
(when update-mtab?
(remove-from-mtab target))))))
+(define swapon
+ (let* ((ptr (dynamic-func "swapon" (dynamic-link)))
+ (proc (pointer->procedure int ptr (list '* int))))
+ (lambda* (device #:optional (flags 0))
+ "Use the block special device at DEVICE for swapping."
+ (let ((ret (proc (string->pointer device) flags))
+ (err (errno)))
+ (unless (zero? ret)
+ (throw 'system-error "swapon" "~S: ~A"
+ (list device (strerror err))
+ (list err)))))))
+
+(define swapoff
+ (let* ((ptr (dynamic-func "swapoff" (dynamic-link)))
+ (proc (pointer->procedure int ptr '(*))))
+ (lambda (device)
+ "Stop using block special device DEVICE for swapping."
+ (let ((ret (proc (string->pointer device)))
+ (err (errno)))
+ (unless (zero? ret)
+ (throw 'system-error "swapff" "~S: ~A"
+ (list device (strerror err))
+ (list err)))))))
+
(define (kernel? pid)
"Return #t if PID designates a \"kernel thread\" rather than a normal
user-land process."
@@ -180,4 +215,130 @@ user-land process."
(scandir "/proc"))
<))
+
+;;;
+;;; Network interfaces.
+;;;
+
+(define SIOCGIFCONF ;from <bits/ioctls.h>
+ (if (string-contains %host-type "linux")
+ #x8912 ;GNU/Linux
+ #xf00801a4)) ;GNU/Hurd
+(define SIOCGIFFLAGS
+ (if (string-contains %host-type "linux")
+ #x8913 ;GNU/Linux
+ #xc4804191)) ;GNU/Hurd
+
+;; Flags and constants from <net/if.h>.
+
+(define IFF_UP #x1) ;Interface is up
+(define IFF_BROADCAST #x2) ;Broadcast address valid.
+(define IFF_LOOPBACK #x8) ;Is a loopback net.
+
+(define IF_NAMESIZE 16) ;maximum interface name size
+
+(define ifconf-struct
+ ;; 'struct ifconf', from <net/if.h>.
+ (list int ;int ifc_len
+ '*)) ;struct ifreq *ifc_ifcu
+
+(define ifreq-struct-size
+ ;; 'struct ifreq' begins with an array of IF_NAMESIZE bytes containing the
+ ;; interface name (nul-terminated), followed by a bunch of stuff. This is
+ ;; its size in bytes.
+ (if (= 8 (sizeof '*))
+ 40
+ 32))
+
+(define %ioctl
+ ;; The most terrible interface, live from Scheme.
+ (pointer->procedure int
+ (dynamic-func "ioctl" (dynamic-link))
+ (list int unsigned-long '*)))
+
+(define (bytevector->string-list bv stride len)
+ "Return the null-terminated strings found in BV every STRIDE bytes. Read at
+most LEN bytes from BV."
+ (let loop ((bytes (take (bytevector->u8-list bv)
+ (min len (bytevector-length bv))))
+ (result '()))
+ (match bytes
+ (()
+ (reverse result))
+ (_
+ (loop (drop bytes stride)
+ (cons (list->string (map integer->char
+ (take-while (negate zero?) bytes)))
+ result))))))
+
+(define* (network-interfaces #:optional sock)
+ "Return the list of existing network interfaces. This is typically limited
+to interfaces that are currently up."
+ (let* ((close? (not sock))
+ (sock (or sock (socket SOCK_STREAM AF_INET 0)))
+ (len (* ifreq-struct-size 10))
+ (reqs (make-bytevector len))
+ (conf (make-c-struct ifconf-struct
+ (list len (bytevector->pointer reqs))))
+ (ret (%ioctl (fileno sock) SIOCGIFCONF conf))
+ (err (errno)))
+ (when close?
+ (close-port sock))
+ (if (zero? ret)
+ (bytevector->string-list reqs ifreq-struct-size
+ (match (parse-c-struct conf ifconf-struct)
+ ((len . _) len)))
+ (throw 'system-error "network-interface-list"
+ "network-interface-list: ~A"
+ (list (strerror err))
+ (list err)))))
+
+(define %interface-line
+ ;; Regexp matching an interface line in Linux's /proc/net/dev.
+ (make-regexp "^[[:blank:]]*([[:alnum:]]+):.*$"))
+
+(define (all-network-interfaces)
+ "Return all the registered network interfaces, including those that are not
+up."
+ (call-with-input-file "/proc/net/dev" ;XXX: Linux-specific
+ (lambda (port)
+ (let loop ((interfaces '()))
+ (let ((line (read-line port)))
+ (cond ((eof-object? line)
+ (reverse interfaces))
+ ((regexp-exec %interface-line line)
+ =>
+ (lambda (match)
+ (loop (cons (match:substring match 1) interfaces))))
+ (else
+ (loop interfaces))))))))
+
+(define (network-interface-flags socket name)
+ "Return a number that is the bit-wise or of 'IFF*' flags for network
+interface NAME."
+ (let ((req (make-bytevector ifreq-struct-size)))
+ (bytevector-copy! (string->utf8 name) 0 req 0
+ (min (string-length name) (- IF_NAMESIZE 1)))
+ (let* ((ret (%ioctl (fileno socket) SIOCGIFFLAGS
+ (bytevector->pointer req)))
+ (err (errno)))
+ (if (zero? ret)
+
+ ;; The 'ifr_flags' field is IF_NAMESIZE bytes after the beginning of
+ ;; 'struct ifreq', and it's a short int.
+ (bytevector-sint-ref req IF_NAMESIZE (native-endianness)
+ (sizeof short))
+
+ (throw 'system-error "network-interface-flags"
+ "network-interface-flags on ~A: ~A"
+ (list name (strerror err))
+ (list err))))))
+
+(define (loopback-network-interface? name)
+ "Return true if NAME designates a loopback network interface."
+ (let* ((sock (socket SOCK_STREAM AF_INET 0))
+ (flags (network-interface-flags sock name)))
+ (close-port sock)
+ (not (zero? (logand flags IFF_LOOPBACK)))))
+
;;; syscalls.scm ends here
diff --git a/guix/profiles.scm b/guix/profiles.scm
index aa88b849e1..18733a6664 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -70,6 +70,7 @@
profile-derivation
generation-number
generation-numbers
+ profile-generations
previous-generation-number
generation-time
generation-file-name))
@@ -561,6 +562,13 @@ former profiles were found."
profiles)
<))))
+(define (profile-generations profile)
+ "Return a list of PROFILE's generations."
+ (let ((generations (generation-numbers profile)))
+ (if (equal? generations '(0))
+ '()
+ generations)))
+
(define (previous-generation-number profile number)
"Return the number of the generation before generation NUMBER of
PROFILE, or 0 if none exists. It could be NUMBER - 1, but it's not the
diff --git a/guix/scripts/offload.scm b/guix/scripts/offload.scm
index b3b502425c..391906ff79 100644
--- a/guix/scripts/offload.scm
+++ b/guix/scripts/offload.scm
@@ -534,10 +534,6 @@ success, #f otherwise."
(build-requirements-features requirements)
(build-machine-features machine))))
-(define (machine-faster? m1 m2)
- "Return #t if M1 is faster than M2."
- (> (build-machine-speed m1) (build-machine-speed m2)))
-
(define (machine-load machine)
"Return the load of MACHINE, divided by the number of parallel builds
allowed on MACHINE."
@@ -558,14 +554,16 @@ allowed on MACHINE."
(_
+inf.0))))) ;something's fishy about MACHINE, so avoid it
-(define (machine-less-loaded? m1 m2)
- "Return #t if the load on M1 is lower than that on M2."
- (< (machine-load m1) (machine-load m2)))
+(define (machine-power-factor m)
+ "Return a factor that aggregates the speed and load of M. The higher the
+better."
+ (/ (build-machine-speed m)
+ (+ 1 (machine-load m))))
(define (machine-less-loaded-or-faster? m1 m2)
- "Return #t if M1 is either less loaded or faster than M2."
- (or (machine-less-loaded? m1 m2)
- (machine-faster? m1 m2)))
+ "Return #t if M1 is either less loaded or faster than M2. (This relation
+defines a total order on machines.)"
+ (> (machine-power-factor m1) (machine-power-factor m2)))
(define (machine-lock-file machine hint)
"Return the name of MACHINE's lock file for HINT."
@@ -610,22 +608,25 @@ allowed on MACHINE."
(list machine1 slot1)
(list machine2 slot2))))))))
- (let ((machines+slots (sort machines+slots
- (undecorate machine-less-loaded-or-faster?))))
+ (let loop ((machines+slots
+ (sort machines+slots
+ (undecorate machine-less-loaded-or-faster?))))
(match machines+slots
- (((best slot) (others slots) ...)
- ;; Release slots from the uninteresting machines.
- (for-each release-build-slot slots)
-
+ (((best slot) others ...)
;; Return the best machine unless it's already overloaded.
(if (< (machine-load best) 2.)
+ (match others
+ (((machines slots) ...)
+ ;; Release slots from the uninteresting machines.
+ (for-each release-build-slot slots)
+
+ ;; Prevent SLOT from being GC'd.
+ (set! %slots (cons slot %slots))
+ best))
(begin
- ;; Prevent SLOT from being GC'd.
- (set! %slots (cons slot %slots))
- best)
- (begin
+ ;; BEST is overloaded, so try the next one.
(release-build-slot slot)
- #f)))
+ (loop others))))
(() #f)))))
(define* (process-request wants-local? system drv features
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 95c0130c95..7cd95167d2 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -716,12 +716,9 @@ more information.~%"))
(leave (_ "profile '~a' does not exist~%")
profile))
((string-null? pattern)
- (let ((numbers (generation-numbers profile)))
- (if (equal? numbers '(0))
- (exit 0)
- (for-each display-and-delete
- (delete current-generation-number
- numbers)))))
+ (for-each display-and-delete
+ (delete current-generation-number
+ (profile-generations profile))))
;; Do not delete the zeroth generation.
((equal? 0 (string->number pattern))
(exit 0))
@@ -828,11 +825,7 @@ more information.~%"))
(leave (_ "profile '~a' does not exist~%")
profile))
((string-null? pattern)
- (let ((numbers (generation-numbers profile)))
- (leave-on-EPIPE
- (if (equal? numbers '(0))
- (exit 0)
- (for-each list-generation numbers)))))
+ (for-each list-generation (profile-generations profile)))
((matching-generations pattern profile)
=>
(lambda (numbers)
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 5dafb84f91..c2ea0e3d97 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -23,6 +23,8 @@
#:use-module (guix packages)
#:use-module (guix derivations)
#:use-module (guix download)
+ #:use-module (guix gexp)
+ #:use-module (guix monads)
#:use-module (gnu packages base)
#:use-module (gnu packages guile)
#:use-module ((gnu packages bootstrap)
@@ -38,34 +40,27 @@
"http://git.savannah.gnu.org/cgit/guix.git/snapshot/guix-master.tar.gz"
)
-(define* (unpack store tarball #:key verbose?)
+(define* (unpack tarball #:key verbose?)
"Return a derivation that unpacks TARBALL into STORE and compiles Scheme
files."
(define builder
- `(begin
- (use-modules (guix build pull))
+ #~(begin
+ (use-modules (guix build pull))
- (build-guix (assoc-ref %outputs "out")
- (assoc-ref %build-inputs "tarball")
+ (build-guix #$output #$tarball
- ;; XXX: This is not perfect, enabling VERBOSE? means
- ;; building a different derivation.
- #:debug-port (if ',verbose?
- (current-error-port)
- (%make-void-port "w"))
- #:tar (assoc-ref %build-inputs "tar")
- #:gzip (assoc-ref %build-inputs "gzip")
- #:gcrypt (assoc-ref %build-inputs "gcrypt"))))
+ ;; XXX: This is not perfect, enabling VERBOSE? means
+ ;; building a different derivation.
+ #:debug-port (if #$verbose?
+ (current-error-port)
+ (%make-void-port "w"))
+ #:tar #$tar
+ #:gzip #$gzip
+ #:gcrypt #$libgcrypt)))
- (build-expression->derivation store "guix-latest" builder
- #:inputs
- `(("tar" ,(package-derivation store tar))
- ("gzip" ,(package-derivation store gzip))
- ("gcrypt" ,(package-derivation store
- libgcrypt))
- ("tarball" ,tarball))
- #:modules '((guix build pull)
- (guix build utils))))
+ (gexp->derivation "guix-latest" builder
+ #:modules '((guix build pull)
+ (guix build utils))))
;;;
@@ -114,6 +109,33 @@ Download and deploy the latest version of Guix.\n"))
(lambda args
(show-version-and-exit "guix pull")))))
+(define what-to-build
+ (store-lift show-what-to-build))
+(define indirect-root-added
+ (store-lift add-indirect-root))
+
+(define* (build-and-install tarball config-dir
+ #:key verbose?)
+ "Build the tool from TARBALL, and install it in CONFIG-DIR."
+ (mlet* %store-monad ((source (unpack tarball #:verbose? verbose?))
+ (source-dir -> (derivation->output-path source))
+ (to-do? (what-to-build (list source))))
+ (if to-do?
+ (mlet* %store-monad ((built? (built-derivations (list source))))
+ (if built?
+ (mlet* %store-monad
+ ((latest -> (string-append config-dir "/latest"))
+ (done (indirect-root-added latest)))
+ (switch-symlinks latest source-dir)
+ (format #t
+ (_ "updated ~a successfully deployed under `~a'~%")
+ %guix-package-name latest)
+ (return #t))
+ (leave (_ "failed to update Guix, check the build log~%"))))
+ (begin
+ (display (_ "Guix already up to date\n"))
+ (return #t)))))
+
(define (guix-pull . args)
(define (parse-options)
;; Return the alist of option values.
@@ -136,20 +158,6 @@ Download and deploy the latest version of Guix.\n"))
(if (assoc-ref opts 'bootstrap?)
%bootstrap-guile
(canonical-package guile-2.0)))))
- (let* ((config-dir (config-directory))
- (source (unpack store tarball
- #:verbose? (assoc-ref opts 'verbose?)))
- (source-dir (derivation->output-path source)))
- (if (show-what-to-build store (list source))
- (if (build-derivations store (list source))
- (let ((latest (string-append config-dir "/latest")))
- (add-indirect-root store latest)
- (switch-symlinks latest source-dir)
- (format #t
- (_ "updated ~a successfully deployed under `~a'~%")
- %guix-package-name latest)
- #t)
- (leave (_ "failed to update Guix, check the build log~%")))
- (begin
- (display (_ "Guix already up to date\n"))
- #t))))))))
+ (run-with-store store
+ (build-and-install tarball (config-directory)
+ #:verbose? (assoc-ref opts 'verbose?))))))))
diff --git a/guix/ui.scm b/guix/ui.scm
index f11c2e9c92..531d922ad9 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -25,6 +25,7 @@
#:use-module (guix packages)
#:use-module (guix build-system)
#:use-module (guix derivations)
+ #:use-module ((guix build utils) #:select (mkdir-p))
#:use-module ((guix licenses) #:select (license? license-name))
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
@@ -370,15 +371,13 @@ exists. Honor the XDG specs,
(cut string-append <> "/guix"))))
(catch 'system-error
(lambda ()
- (mkdir dir)
+ (mkdir-p dir)
dir)
(lambda args
- (match (system-error-errno args)
- ((or EEXIST 0)
- dir)
- (err
- (leave (_ "failed to create configuration directory `~a': ~a~%")
- dir (strerror err))))))))
+ (let ((err (system-error-errno args)))
+ ;; ERR is necessarily different from EEXIST.
+ (leave (_ "failed to create configuration directory `~a': ~a~%")
+ dir (strerror err)))))))
(define* (fill-paragraph str width #:optional (column 0))
"Fill STR such that each line contains at most WIDTH characters, assuming
diff --git a/guix/utils.scm b/guix/utils.scm
index b61ff2477d..34a5e6c971 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -600,8 +600,9 @@ REPLACEMENT."
"Call PROC with a name of a temporary file and open output port to that
file; close the file and delete it when leaving the dynamic extent of this
call."
- (let* ((template (string-copy "guix-file.XXXXXX"))
- (out (mkstemp! template)))
+ (let* ((directory (or (getenv "TMPDIR") "/tmp"))
+ (template (string-append directory "/guix-file.XXXXXX"))
+ (out (mkstemp! template)))
(dynamic-wind
(lambda ()
#t)