summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2014-09-14 21:39:51 +0200
committerLudovic Courtès <ludo@gnu.org>2014-09-14 23:49:02 +0200
commit7585016f53e2e8be1f82ed303ae084464422c2a8 (patch)
treec318e4e69fd0aa7d24d5631c2ff62a0df30c1245
parent150d8e6414cad90e1da7d767251b874688e89e26 (diff)
syscalls: Add 'network-interfaces'.
* guix/build/syscalls.scm (SIOCGIFCONF, ifconf-struct, ifreq-struct-size): New variables. (%ioctl, bytevector->string-list, network-interfaces): New procedures. * tests/syscalls.scm ("network-interfaces"): New test.
-rw-r--r--guix/build/syscalls.scm67
-rw-r--r--tests/syscalls.scm8
2 files changed, 73 insertions, 2 deletions
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 7a1bad73311..cd2797219fd 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -30,7 +30,8 @@
30 MS_MOVE 30 MS_MOVE
31 mount 31 mount
32 umount 32 umount
33 processes)) 33 processes
34 network-interfaces))
34 35
35;;; Commentary: 36;;; Commentary:
36;;; 37;;;
@@ -180,4 +181,68 @@ user-land process."
180 (scandir "/proc")) 181 (scandir "/proc"))
181 <)) 182 <))
182 183
184
185;;;
186;;; Network interfaces.
187;;;
188
189(define SIOCGIFCONF ;from <bits/ioctls.h>
190 (if (string-contains %host-type "linux")
191 #x8912 ;GNU/Linux
192 #xf00801a4)) ;GNU/Hurd
193
194(define ifconf-struct
195 ;; 'struct ifconf', from <net/if.h>.
196 (list int ;int ifc_len
197 '*)) ;struct ifreq *ifc_ifcu
198
199(define ifreq-struct-size
200 ;; 'struct ifreq' begins with a char array containing the interface name,
201 ;; followed by a bunch of stuff. This is its size in bytes.
202 (if (= 8 (sizeof '*))
203 40
204 32))
205
206(define %ioctl
207 ;; The most terrible interface, live from Scheme.
208 (pointer->procedure int
209 (dynamic-func "ioctl" (dynamic-link))
210 (list int unsigned-long '*)))
211
212(define (bytevector->string-list bv stride len)
213 "Return the null-terminated strings found in BV every STRIDE bytes. Read at
214most LEN bytes from BV."
215 (let loop ((bytes (take (bytevector->u8-list bv)
216 (min len (bytevector-length bv))))
217 (result '()))
218 (match bytes
219 (()
220 (reverse result))
221 (_
222 (loop (drop bytes stride)
223 (cons (list->string (map integer->char
224 (take-while (negate zero?) bytes)))
225 result))))))
226
227(define* (network-interfaces #:optional sock)
228 "Return the list of existing network interfaces."
229 (let* ((close? (not sock))
230 (sock (or sock (socket SOCK_STREAM AF_INET 0)))
231 (len (* ifreq-struct-size 10))
232 (reqs (make-bytevector len))
233 (conf (make-c-struct ifconf-struct
234 (list len (bytevector->pointer reqs))))
235 (ret (%ioctl (fileno sock) SIOCGIFCONF conf))
236 (err (errno)))
237 (when close?
238 (close-port sock))
239 (if (zero? ret)
240 (bytevector->string-list reqs ifreq-struct-size
241 (match (parse-c-struct conf ifconf-struct)
242 ((len . _) len)))
243 (throw 'system-error "network-interface-list"
244 "network-interface-list: ~A"
245 (list (strerror err))
246 (list err)))))
247
183;;; syscalls.scm ends here 248;;; syscalls.scm ends here
diff --git a/tests/syscalls.scm b/tests/syscalls.scm
index ab34fc825bb..fa6b67bf398 100644
--- a/tests/syscalls.scm
+++ b/tests/syscalls.scm
@@ -18,7 +18,8 @@
18 18
19(define-module (test-syscalls) 19(define-module (test-syscalls)
20 #:use-module (guix build syscalls) 20 #:use-module (guix build syscalls)
21 #:use-module (srfi srfi-64)) 21 #:use-module (srfi srfi-64)
22 #:use-module (ice-9 match))
22 23
23;; Test the (guix build syscalls) module, although there's not much that can 24;; Test the (guix build syscalls) module, although there's not much that can
24;; actually be tested without being root. 25;; actually be tested without being root.
@@ -42,6 +43,11 @@
42 ;; Both return values have been encountered in the wild. 43 ;; Both return values have been encountered in the wild.
43 (memv (system-error-errno args) (list EPERM ENOENT))))) 44 (memv (system-error-errno args) (list EPERM ENOENT)))))
44 45
46(test-assert "network-interfaces"
47 (match (network-interfaces)
48 (((? string? names) ..1)
49 (member "lo" names))))
50
45(test-end) 51(test-end)
46 52
47 53