diff options
| -rw-r--r-- | guix/build/syscalls.scm | 69 | ||||
| -rw-r--r-- | guix/nar.scm | 4 | ||||
| -rw-r--r-- | guix/utils.scm | 75 | ||||
| -rw-r--r-- | tests/syscalls.scm | 88 | ||||
| -rw-r--r-- | tests/utils.scm | 82 |
5 files changed, 160 insertions, 158 deletions
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index a9cd6e93c89..86723c23c7c 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm | |||
| @@ -65,6 +65,7 @@ | |||
| 65 | processes | 65 | processes |
| 66 | mkdtemp! | 66 | mkdtemp! |
| 67 | pivot-root | 67 | pivot-root |
| 68 | fcntl-flock | ||
| 68 | 69 | ||
| 69 | CLONE_CHILD_CLEARTID | 70 | CLONE_CHILD_CLEARTID |
| 70 | CLONE_CHILD_SETTID | 71 | CLONE_CHILD_SETTID |
| @@ -639,6 +640,74 @@ system to PUT-OLD." | |||
| 639 | 640 | ||
| 640 | 641 | ||
| 641 | ;;; | 642 | ;;; |
| 643 | ;;; Advisory file locking. | ||
| 644 | ;;; | ||
| 645 | |||
| 646 | (define %struct-flock | ||
| 647 | ;; 'struct flock' from <fcntl.h>. | ||
| 648 | (list short ; l_type | ||
| 649 | short ; l_whence | ||
| 650 | size_t ; l_start | ||
| 651 | size_t ; l_len | ||
| 652 | int)) ; l_pid | ||
| 653 | |||
| 654 | (define F_SETLKW | ||
| 655 | ;; On Linux-based systems, this is usually 7, but not always | ||
| 656 | ;; (exceptions include SPARC.) On GNU/Hurd, it's 9. | ||
| 657 | (cond ((string-contains %host-type "sparc") 9) ; sparc-*-linux-gnu | ||
| 658 | ((string-contains %host-type "linux") 7) ; *-linux-gnu | ||
| 659 | (else 9))) ; *-gnu* | ||
| 660 | |||
| 661 | (define F_SETLK | ||
| 662 | ;; Likewise: GNU/Hurd and SPARC use 8, while the others typically use 6. | ||
| 663 | (cond ((string-contains %host-type "sparc") 8) ; sparc-*-linux-gnu | ||
| 664 | ((string-contains %host-type "linux") 6) ; *-linux-gnu | ||
| 665 | (else 8))) ; *-gnu* | ||
| 666 | |||
| 667 | (define F_xxLCK | ||
| 668 | ;; The F_RDLCK, F_WRLCK, and F_UNLCK constants. | ||
| 669 | (cond ((string-contains %host-type "sparc") #(1 2 3)) ; sparc-*-linux-gnu | ||
| 670 | ((string-contains %host-type "hppa") #(1 2 3)) ; hppa-*-linux-gnu | ||
| 671 | ((string-contains %host-type "linux") #(0 1 2)) ; *-linux-gnu | ||
| 672 | (else #(1 2 3)))) ; *-gnu* | ||
| 673 | |||
| 674 | (define fcntl-flock | ||
| 675 | (let ((proc (syscall->procedure int "fcntl" `(,int ,int *)))) | ||
| 676 | (lambda* (fd-or-port operation #:key (wait? #t)) | ||
| 677 | "Perform locking OPERATION on the file beneath FD-OR-PORT. OPERATION | ||
| 678 | must be a symbol, one of 'read-lock, 'write-lock, or 'unlock. When WAIT? is | ||
| 679 | true, block until the lock is acquired; otherwise, thrown an 'flock-error' | ||
| 680 | exception if it's already taken." | ||
| 681 | (define (operation->int op) | ||
| 682 | (case op | ||
| 683 | ((read-lock) (vector-ref F_xxLCK 0)) | ||
| 684 | ((write-lock) (vector-ref F_xxLCK 1)) | ||
| 685 | ((unlock) (vector-ref F_xxLCK 2)) | ||
| 686 | (else (error "invalid fcntl-flock operation" op)))) | ||
| 687 | |||
| 688 | (define fd | ||
| 689 | (if (port? fd-or-port) | ||
| 690 | (fileno fd-or-port) | ||
| 691 | fd-or-port)) | ||
| 692 | |||
| 693 | ;; XXX: 'fcntl' is a vararg function, but here we happily use the | ||
| 694 | ;; standard ABI; crossing fingers. | ||
| 695 | (let ((err (proc fd | ||
| 696 | (if wait? | ||
| 697 | F_SETLKW ; lock & wait | ||
| 698 | F_SETLK) ; non-blocking attempt | ||
| 699 | (make-c-struct %struct-flock | ||
| 700 | (list (operation->int operation) | ||
| 701 | SEEK_SET | ||
| 702 | 0 0 ; whole file | ||
| 703 | 0))))) | ||
| 704 | (or (zero? err) | ||
| 705 | |||
| 706 | ;; Presumably we got EAGAIN or so. | ||
| 707 | (throw 'flock-error (errno))))))) | ||
| 708 | |||
| 709 | |||
| 710 | ;;; | ||
| 642 | ;;; Network interfaces. | 711 | ;;; Network interfaces. |
| 643 | ;;; | 712 | ;;; |
| 644 | 713 | ||
diff --git a/guix/nar.scm b/guix/nar.scm index 43e52107521..739d3d3a57c 100644 --- a/guix/nar.scm +++ b/guix/nar.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; Copyright © 2014 Mark H Weaver <mhw@netris.org> | 3 | ;;; Copyright © 2014 Mark H Weaver <mhw@netris.org> |
| 4 | ;;; | 4 | ;;; |
| 5 | ;;; This file is part of GNU Guix. | 5 | ;;; This file is part of GNU Guix. |
| @@ -18,8 +18,8 @@ | |||
| 18 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | 18 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. |
| 19 | 19 | ||
| 20 | (define-module (guix nar) | 20 | (define-module (guix nar) |
| 21 | #:use-module (guix utils) | ||
| 22 | #:use-module (guix serialization) | 21 | #:use-module (guix serialization) |
| 22 | #:use-module (guix build syscalls) | ||
| 23 | #:use-module ((guix build utils) | 23 | #:use-module ((guix build utils) |
| 24 | #:select (delete-file-recursively with-directory-excursion)) | 24 | #:select (delete-file-recursively with-directory-excursion)) |
| 25 | #:use-module (guix store) | 25 | #:use-module (guix store) |
diff --git a/guix/utils.scm b/guix/utils.scm index f18bbd19acf..d924e434bd1 100644 --- a/guix/utils.scm +++ b/guix/utils.scm | |||
| @@ -34,7 +34,7 @@ | |||
| 34 | #:use-module ((rnrs bytevectors) #:select (bytevector-u8-set!)) | 34 | #:use-module ((rnrs bytevectors) #:select (bytevector-u8-set!)) |
| 35 | #:use-module (guix combinators) | 35 | #:use-module (guix combinators) |
| 36 | #:use-module ((guix build utils) #:select (dump-port)) | 36 | #:use-module ((guix build utils) #:select (dump-port)) |
| 37 | #:use-module ((guix build syscalls) #:select (errno mkdtemp!)) | 37 | #:use-module ((guix build syscalls) #:select (mkdtemp!)) |
| 38 | #:use-module (ice-9 vlist) | 38 | #:use-module (ice-9 vlist) |
| 39 | #:use-module (ice-9 format) | 39 | #:use-module (ice-9 format) |
| 40 | #:autoload (ice-9 popen) (open-pipe*) | 40 | #:autoload (ice-9 popen) (open-pipe*) |
| @@ -47,7 +47,6 @@ | |||
| 47 | #:export (bytevector->base16-string | 47 | #:export (bytevector->base16-string |
| 48 | base16-string->bytevector | 48 | base16-string->bytevector |
| 49 | 49 | ||
| 50 | fcntl-flock | ||
| 51 | strip-keyword-arguments | 50 | strip-keyword-arguments |
| 52 | default-keyword-arguments | 51 | default-keyword-arguments |
| 53 | substitute-keyword-arguments | 52 | substitute-keyword-arguments |
| @@ -340,78 +339,6 @@ This procedure returns #t on success." | |||
| 340 | 339 | ||
| 341 | 340 | ||
| 342 | ;;; | 341 | ;;; |
| 343 | ;;; Advisory file locking. | ||
| 344 | ;;; | ||
| 345 | |||
| 346 | (define %struct-flock | ||
| 347 | ;; 'struct flock' from <fcntl.h>. | ||
| 348 | (list short ; l_type | ||
| 349 | short ; l_whence | ||
| 350 | size_t ; l_start | ||
| 351 | size_t ; l_len | ||
| 352 | int)) ; l_pid | ||
| 353 | |||
| 354 | (define F_SETLKW | ||
| 355 | ;; On Linux-based systems, this is usually 7, but not always | ||
| 356 | ;; (exceptions include SPARC.) On GNU/Hurd, it's 9. | ||
| 357 | (compile-time-value | ||
| 358 | (cond ((string-contains %host-type "sparc") 9) ; sparc-*-linux-gnu | ||
| 359 | ((string-contains %host-type "linux") 7) ; *-linux-gnu | ||
| 360 | (else 9)))) ; *-gnu* | ||
| 361 | |||
| 362 | (define F_SETLK | ||
| 363 | ;; Likewise: GNU/Hurd and SPARC use 8, while the others typically use 6. | ||
| 364 | (compile-time-value | ||
| 365 | (cond ((string-contains %host-type "sparc") 8) ; sparc-*-linux-gnu | ||
| 366 | ((string-contains %host-type "linux") 6) ; *-linux-gnu | ||
| 367 | (else 8)))) ; *-gnu* | ||
| 368 | |||
| 369 | (define F_xxLCK | ||
| 370 | ;; The F_RDLCK, F_WRLCK, and F_UNLCK constants. | ||
| 371 | (compile-time-value | ||
| 372 | (cond ((string-contains %host-type "sparc") #(1 2 3)) ; sparc-*-linux-gnu | ||
| 373 | ((string-contains %host-type "hppa") #(1 2 3)) ; hppa-*-linux-gnu | ||
| 374 | ((string-contains %host-type "linux") #(0 1 2)) ; *-linux-gnu | ||
| 375 | (else #(1 2 3))))) ; *-gnu* | ||
| 376 | |||
| 377 | (define fcntl-flock | ||
| 378 | (let* ((ptr (dynamic-func "fcntl" (dynamic-link))) | ||
| 379 | (proc (pointer->procedure int ptr `(,int ,int *)))) | ||
| 380 | (lambda* (fd-or-port operation #:key (wait? #t)) | ||
| 381 | "Perform locking OPERATION on the file beneath FD-OR-PORT. OPERATION | ||
| 382 | must be a symbol, one of 'read-lock, 'write-lock, or 'unlock. When WAIT? is | ||
| 383 | true, block until the lock is acquired; otherwise, thrown an 'flock-error' | ||
| 384 | exception if it's already taken." | ||
| 385 | (define (operation->int op) | ||
| 386 | (case op | ||
| 387 | ((read-lock) (vector-ref F_xxLCK 0)) | ||
| 388 | ((write-lock) (vector-ref F_xxLCK 1)) | ||
| 389 | ((unlock) (vector-ref F_xxLCK 2)) | ||
| 390 | (else (error "invalid fcntl-flock operation" op)))) | ||
| 391 | |||
| 392 | (define fd | ||
| 393 | (if (port? fd-or-port) | ||
| 394 | (fileno fd-or-port) | ||
| 395 | fd-or-port)) | ||
| 396 | |||
| 397 | ;; XXX: 'fcntl' is a vararg function, but here we happily use the | ||
| 398 | ;; standard ABI; crossing fingers. | ||
| 399 | (let ((err (proc fd | ||
| 400 | (if wait? | ||
| 401 | F_SETLKW ; lock & wait | ||
| 402 | F_SETLK) ; non-blocking attempt | ||
| 403 | (make-c-struct %struct-flock | ||
| 404 | (list (operation->int operation) | ||
| 405 | SEEK_SET | ||
| 406 | 0 0 ; whole file | ||
| 407 | 0))))) | ||
| 408 | (or (zero? err) | ||
| 409 | |||
| 410 | ;; Presumably we got EAGAIN or so. | ||
| 411 | (throw 'flock-error (errno))))))) | ||
| 412 | |||
| 413 | |||
| 414 | ;;; | ||
| 415 | ;;; Keyword arguments. | 342 | ;;; Keyword arguments. |
| 416 | ;;; | 343 | ;;; |
| 417 | 344 | ||
diff --git a/tests/syscalls.scm b/tests/syscalls.scm index 0b73fb4b0cd..73fa8a7acfa 100644 --- a/tests/syscalls.scm +++ b/tests/syscalls.scm | |||
| @@ -29,6 +29,10 @@ | |||
| 29 | ;; Test the (guix build syscalls) module, although there's not much that can | 29 | ;; Test the (guix build syscalls) module, although there's not much that can |
| 30 | ;; actually be tested without being root. | 30 | ;; actually be tested without being root. |
| 31 | 31 | ||
| 32 | (define temp-file | ||
| 33 | (string-append "t-utils-" (number->string (getpid)))) | ||
| 34 | |||
| 35 | |||
| 32 | (test-begin "syscalls") | 36 | (test-begin "syscalls") |
| 33 | 37 | ||
| 34 | (test-equal "mount, ENOENT" | 38 | (test-equal "mount, ENOENT" |
| @@ -172,6 +176,88 @@ | |||
| 172 | (status:exit-val status)))) | 176 | (status:exit-val status)))) |
| 173 | (eq? #t result)))))))) | 177 | (eq? #t result)))))))) |
| 174 | 178 | ||
| 179 | (false-if-exception (delete-file temp-file)) | ||
| 180 | (test-equal "fcntl-flock wait" | ||
| 181 | 42 ; the child's exit status | ||
| 182 | (let ((file (open-file temp-file "w0b"))) | ||
| 183 | ;; Acquire an exclusive lock. | ||
| 184 | (fcntl-flock file 'write-lock) | ||
| 185 | (match (primitive-fork) | ||
| 186 | (0 | ||
| 187 | (dynamic-wind | ||
| 188 | (const #t) | ||
| 189 | (lambda () | ||
| 190 | ;; Reopen FILE read-only so we can have a read lock. | ||
| 191 | (let ((file (open-file temp-file "r0b"))) | ||
| 192 | ;; Wait until we can acquire the lock. | ||
| 193 | (fcntl-flock file 'read-lock) | ||
| 194 | (primitive-exit (read file))) | ||
| 195 | (primitive-exit 1)) | ||
| 196 | (lambda () | ||
| 197 | (primitive-exit 2)))) | ||
| 198 | (pid | ||
| 199 | ;; Write garbage and wait. | ||
| 200 | (display "hello, world!" file) | ||
| 201 | (force-output file) | ||
| 202 | (sleep 1) | ||
| 203 | |||
| 204 | ;; Write the real answer. | ||
| 205 | (seek file 0 SEEK_SET) | ||
| 206 | (truncate-file file 0) | ||
| 207 | (write 42 file) | ||
| 208 | (force-output file) | ||
| 209 | |||
| 210 | ;; Unlock, which should let the child continue. | ||
| 211 | (fcntl-flock file 'unlock) | ||
| 212 | |||
| 213 | (match (waitpid pid) | ||
| 214 | ((_ . status) | ||
| 215 | (let ((result (status:exit-val status))) | ||
| 216 | (close-port file) | ||
| 217 | result))))))) | ||
| 218 | |||
| 219 | (test-equal "fcntl-flock non-blocking" | ||
| 220 | EAGAIN ; the child's exit status | ||
| 221 | (match (pipe) | ||
| 222 | ((input . output) | ||
| 223 | (match (primitive-fork) | ||
| 224 | (0 | ||
| 225 | (dynamic-wind | ||
| 226 | (const #t) | ||
| 227 | (lambda () | ||
| 228 | (close-port output) | ||
| 229 | |||
| 230 | ;; Wait for the green light. | ||
| 231 | (read-char input) | ||
| 232 | |||
| 233 | ;; Open FILE read-only so we can have a read lock. | ||
| 234 | (let ((file (open-file temp-file "w0"))) | ||
| 235 | (catch 'flock-error | ||
| 236 | (lambda () | ||
| 237 | ;; This attempt should throw EAGAIN. | ||
| 238 | (fcntl-flock file 'write-lock #:wait? #f)) | ||
| 239 | (lambda (key errno) | ||
| 240 | (primitive-exit (pk 'errno errno))))) | ||
| 241 | (primitive-exit -1)) | ||
| 242 | (lambda () | ||
| 243 | (primitive-exit -2)))) | ||
| 244 | (pid | ||
| 245 | (close-port input) | ||
| 246 | (let ((file (open-file temp-file "w0"))) | ||
| 247 | ;; Acquire an exclusive lock. | ||
| 248 | (fcntl-flock file 'write-lock) | ||
| 249 | |||
| 250 | ;; Tell the child to continue. | ||
| 251 | (write 'green-light output) | ||
| 252 | (force-output output) | ||
| 253 | |||
| 254 | (match (waitpid pid) | ||
| 255 | ((_ . status) | ||
| 256 | (let ((result (status:exit-val status))) | ||
| 257 | (fcntl-flock file 'unlock) | ||
| 258 | (close-port file) | ||
| 259 | result))))))))) | ||
| 260 | |||
| 175 | (test-assert "all-network-interface-names" | 261 | (test-assert "all-network-interface-names" |
| 176 | (match (all-network-interface-names) | 262 | (match (all-network-interface-names) |
| 177 | (((? string? names) ..1) | 263 | (((? string? names) ..1) |
| @@ -303,3 +389,5 @@ | |||
| 303 | 0)) | 389 | 0)) |
| 304 | 390 | ||
| 305 | (test-end) | 391 | (test-end) |
| 392 | |||
| 393 | (false-if-exception (delete-file temp-file)) | ||
diff --git a/tests/utils.scm b/tests/utils.scm index a54482e94ce..6590ed91cf8 100644 --- a/tests/utils.scm +++ b/tests/utils.scm | |||
| @@ -168,88 +168,6 @@ | |||
| 168 | (call-with-decompressed-port 'xz (open-file temp-file "r0b") | 168 | (call-with-decompressed-port 'xz (open-file temp-file "r0b") |
| 169 | get-bytevector-all)))) | 169 | get-bytevector-all)))) |
| 170 | 170 | ||
| 171 | (false-if-exception (delete-file temp-file)) | ||
| 172 | (test-equal "fcntl-flock wait" | ||
| 173 | 42 ; the child's exit status | ||
| 174 | (let ((file (open-file temp-file "w0b"))) | ||
| 175 | ;; Acquire an exclusive lock. | ||
| 176 | (fcntl-flock file 'write-lock) | ||
| 177 | (match (primitive-fork) | ||
| 178 | (0 | ||
| 179 | (dynamic-wind | ||
| 180 | (const #t) | ||
| 181 | (lambda () | ||
| 182 | ;; Reopen FILE read-only so we can have a read lock. | ||
| 183 | (let ((file (open-file temp-file "r0b"))) | ||
| 184 | ;; Wait until we can acquire the lock. | ||
| 185 | (fcntl-flock file 'read-lock) | ||
| 186 | (primitive-exit (read file))) | ||
| 187 | (primitive-exit 1)) | ||
| 188 | (lambda () | ||
| 189 | (primitive-exit 2)))) | ||
| 190 | (pid | ||
| 191 | ;; Write garbage and wait. | ||
| 192 | (display "hello, world!" file) | ||
| 193 | (force-output file) | ||
| 194 | (sleep 1) | ||
| 195 | |||
| 196 | ;; Write the real answer. | ||
| 197 | (seek file 0 SEEK_SET) | ||
| 198 | (truncate-file file 0) | ||
| 199 | (write 42 file) | ||
| 200 | (force-output file) | ||
| 201 | |||
| 202 | ;; Unlock, which should let the child continue. | ||
| 203 | (fcntl-flock file 'unlock) | ||
| 204 | |||
| 205 | (match (waitpid pid) | ||
| 206 | ((_ . status) | ||
| 207 | (let ((result (status:exit-val status))) | ||
| 208 | (close-port file) | ||
| 209 | result))))))) | ||
| 210 | |||
| 211 | (test-equal "fcntl-flock non-blocking" | ||
| 212 | EAGAIN ; the child's exit status | ||
| 213 | (match (pipe) | ||
| 214 | ((input . output) | ||
| 215 | (match (primitive-fork) | ||
| 216 | (0 | ||
| 217 | (dynamic-wind | ||
| 218 | (const #t) | ||
| 219 | (lambda () | ||
| 220 | (close-port output) | ||
| 221 | |||
| 222 | ;; Wait for the green light. | ||
| 223 | (read-char input) | ||
| 224 | |||
| 225 | ;; Open FILE read-only so we can have a read lock. | ||
| 226 | (let ((file (open-file temp-file "w0"))) | ||
| 227 | (catch 'flock-error | ||
| 228 | (lambda () | ||
| 229 | ;; This attempt should throw EAGAIN. | ||
| 230 | (fcntl-flock file 'write-lock #:wait? #f)) | ||
| 231 | (lambda (key errno) | ||
| 232 | (primitive-exit (pk 'errno errno))))) | ||
| 233 | (primitive-exit -1)) | ||
| 234 | (lambda () | ||
| 235 | (primitive-exit -2)))) | ||
| 236 | (pid | ||
| 237 | (close-port input) | ||
| 238 | (let ((file (open-file temp-file "w0"))) | ||
| 239 | ;; Acquire an exclusive lock. | ||
| 240 | (fcntl-flock file 'write-lock) | ||
| 241 | |||
| 242 | ;; Tell the child to continue. | ||
| 243 | (write 'green-light output) | ||
| 244 | (force-output output) | ||
| 245 | |||
| 246 | (match (waitpid pid) | ||
| 247 | ((_ . status) | ||
| 248 | (let ((result (status:exit-val status))) | ||
| 249 | (fcntl-flock file 'unlock) | ||
| 250 | (close-port file) | ||
| 251 | result))))))))) | ||
| 252 | |||
| 253 | ;; This is actually in (guix store). | 171 | ;; This is actually in (guix store). |
| 254 | (test-equal "store-path-package-name" | 172 | (test-equal "store-path-package-name" |
| 255 | "bash-4.2-p24" | 173 | "bash-4.2-p24" |
