summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guix/build/syscalls.scm53
-rw-r--r--tests/syscalls.scm17
2 files changed, 67 insertions, 3 deletions
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index cd2797219f..06f69e119e 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -31,7 +31,13 @@
mount
umount
processes
- network-interfaces))
+
+ IFF_UP
+ IFF_BROADCAST
+ IFF_LOOPBACK
+ network-interfaces
+ network-interface-flags
+ loopback-network-interface?))
;;; Commentary:
;;;
@@ -190,6 +196,18 @@ user-land process."
(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>.
@@ -197,8 +215,9 @@ user-land process."
'*)) ;struct ifreq *ifc_ifcu
(define ifreq-struct-size
- ;; 'struct ifreq' begins with a char array containing the interface name,
- ;; followed by a bunch of stuff. This is its size in bytes.
+ ;; '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))
@@ -245,4 +264,32 @@ most LEN bytes from BV."
(list (strerror err))
(list err)))))
+(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/tests/syscalls.scm b/tests/syscalls.scm
index fa6b67bf39..c3550ac31a 100644
--- a/tests/syscalls.scm
+++ b/tests/syscalls.scm
@@ -48,6 +48,23 @@
(((? string? names) ..1)
(member "lo" names))))
+(test-assert "network-interface-flags"
+ (let* ((sock (socket SOCK_STREAM AF_INET 0))
+ (flags (network-interface-flags sock "lo")))
+ (close-port sock)
+ (and (not (zero? (logand flags IFF_LOOPBACK)))
+ (not (zero? (logand flags IFF_UP))))))
+
+(test-equal "loopback-network-interface?"
+ ENODEV
+ (and (loopback-network-interface? "lo")
+ (catch 'system-error
+ (lambda ()
+ (loopback-network-interface? "nonexistent")
+ #f)
+ (lambda args
+ (system-error-errno args)))))
+
(test-end)