diff options
| -rw-r--r-- | guix/build/syscalls.scm | 112 | ||||
| -rw-r--r-- | tests/syscalls.scm | 16 |
2 files changed, 121 insertions, 7 deletions
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index b19a7a271bd..552343a481d 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> | 3 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> |
| 4 | ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org> | 4 | ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org> |
| 5 | ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> | 5 | ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> |
| @@ -54,7 +54,18 @@ | |||
| 54 | UMOUNT_NOFOLLOW | 54 | UMOUNT_NOFOLLOW |
| 55 | 55 | ||
| 56 | restart-on-EINTR | 56 | restart-on-EINTR |
| 57 | |||
| 58 | mount? | ||
| 59 | mount-device-number | ||
| 60 | mount-source | ||
| 61 | mount-point | ||
| 62 | mount-type | ||
| 63 | mount-options | ||
| 64 | mount-flags | ||
| 65 | |||
| 66 | mounts | ||
| 57 | mount-points | 67 | mount-points |
| 68 | |||
| 58 | swapon | 69 | swapon |
| 59 | swapoff | 70 | swapoff |
| 60 | 71 | ||
| @@ -521,17 +532,106 @@ constants from <sys/mount.h>." | |||
| 521 | (when update-mtab? | 532 | (when update-mtab? |
| 522 | (remove-from-mtab target))))) | 533 | (remove-from-mtab target))))) |
| 523 | 534 | ||
| 524 | (define (mount-points) | 535 | ;; Mount point information. |
| 525 | "Return the mounts points for currently mounted file systems." | 536 | (define-record-type <mount> |
| 526 | (call-with-input-file "/proc/mounts" | 537 | (%mount source point devno type options) |
| 538 | mount? | ||
| 539 | (devno mount-device-number) ;st_dev | ||
| 540 | (source mount-source) ;string | ||
| 541 | (point mount-point) ;string | ||
| 542 | (type mount-type) ;string | ||
| 543 | (options mount-options)) ;string | ||
| 544 | |||
| 545 | (define (option-string->mount-flags str) | ||
| 546 | "Parse the \"option string\" STR as it appears in /proc/mounts and similar, | ||
| 547 | and return two values: a mount bitmask (inclusive or of MS_* constants), and | ||
| 548 | the remaining unprocessed options." | ||
| 549 | ;; Why do we need to do this? Because mount flags and mount options are | ||
| 550 | ;; often lumped together; this is the case in /proc/mounts & co., so we need | ||
| 551 | ;; to extract the bits that actually correspond to mount flags. | ||
| 552 | |||
| 553 | (define not-comma | ||
| 554 | (char-set-complement (char-set #\,))) | ||
| 555 | |||
| 556 | (define lst | ||
| 557 | (string-tokenize str not-comma)) | ||
| 558 | |||
| 559 | (let loop ((options lst) | ||
| 560 | (mask 0) | ||
| 561 | (remainder '())) | ||
| 562 | (match options | ||
| 563 | (() | ||
| 564 | (values mask (string-concatenate-reverse remainder))) | ||
| 565 | ((head . tail) | ||
| 566 | (letrec-syntax ((match-options (syntax-rules (=>) | ||
| 567 | ((_) | ||
| 568 | (loop tail mask | ||
| 569 | (cons head remainder))) | ||
| 570 | ((_ (str => bit) rest ...) | ||
| 571 | (if (string=? str head) | ||
| 572 | (loop tail (logior bit mask) | ||
| 573 | remainder) | ||
| 574 | (match-options rest ...)))))) | ||
| 575 | (match-options ("rw" => 0) | ||
| 576 | ("ro" => MS_RDONLY) | ||
| 577 | ("nosuid" => MS_NOSUID) | ||
| 578 | ("nodev" => MS_NODEV) | ||
| 579 | ("noexec" => MS_NOEXEC) | ||
| 580 | ("relatime" => MS_RELATIME) | ||
| 581 | ("noatime" => MS_NOATIME))))))) | ||
| 582 | |||
| 583 | (define (mount-flags mount) | ||
| 584 | "Return the mount flags of MOUNT, a <mount> record, as an inclusive or of | ||
| 585 | MS_* constants." | ||
| 586 | (option-string->mount-flags (mount-options mount))) | ||
| 587 | |||
| 588 | (define (octal-decode str) | ||
| 589 | "Decode octal escapes from STR and return the corresponding string. STR may | ||
| 590 | look like this: \"white\\040space\", which is decoded as \"white space\"." | ||
| 591 | (define char-set:octal | ||
| 592 | (char-set #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7)) | ||
| 593 | (define (octal? c) | ||
| 594 | (char-set-contains? char-set:octal c)) | ||
| 595 | |||
| 596 | (let loop ((chars (string->list str)) | ||
| 597 | (result '())) | ||
| 598 | (match chars | ||
| 599 | (() | ||
| 600 | (list->string (reverse result))) | ||
| 601 | ((#\\ (? octal? a) (? octal? b) (? octal? c) . rest) | ||
| 602 | (loop rest | ||
| 603 | (cons (integer->char | ||
| 604 | (string->number (list->string (list a b c)) 8)) | ||
| 605 | result))) | ||
| 606 | ((head . tail) | ||
| 607 | (loop tail (cons head result)))))) | ||
| 608 | |||
| 609 | (define (mounts) | ||
| 610 | "Return the list of mounts (<mount> records) visible in the namespace of the | ||
| 611 | current process." | ||
| 612 | (define (string->device-number str) | ||
| 613 | (match (string-split str #\:) | ||
| 614 | (((= string->number major) (= string->number minor)) | ||
| 615 | (+ (* major 256) minor)))) | ||
| 616 | |||
| 617 | (call-with-input-file "/proc/self/mountinfo" | ||
| 527 | (lambda (port) | 618 | (lambda (port) |
| 528 | (let loop ((result '())) | 619 | (let loop ((result '())) |
| 529 | (let ((line (read-line port))) | 620 | (let ((line (read-line port))) |
| 530 | (if (eof-object? line) | 621 | (if (eof-object? line) |
| 531 | (reverse result) | 622 | (reverse result) |
| 532 | (match (string-tokenize line) | 623 | (match (string-tokenize line) |
| 533 | ((source mount-point _ ...) | 624 | ((id parent-id major:minor root mount-point |
| 534 | (loop (cons mount-point result)))))))))) | 625 | options _ type source _ ...) |
| 626 | (let ((devno (string->device-number major:minor))) | ||
| 627 | (loop (cons (%mount (octal-decode source) | ||
| 628 | (octal-decode mount-point) | ||
| 629 | devno type options) | ||
| 630 | result))))))))))) | ||
| 631 | |||
| 632 | (define (mount-points) | ||
| 633 | "Return the mounts points for currently mounted file systems." | ||
| 634 | (map mount-point (mounts))) | ||
| 535 | 635 | ||
| 536 | (define swapon | 636 | (define swapon |
| 537 | (let ((proc (syscall->procedure int "swapon" (list '* int)))) | 637 | (let ((proc (syscall->procedure int "swapon" (list '* int)))) |
diff --git a/tests/syscalls.scm b/tests/syscalls.scm index 09aa228e8e5..706dd4177fc 100644 --- a/tests/syscalls.scm +++ b/tests/syscalls.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> | 3 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> |
| 4 | ;;; Copyright © 2020 Simon South <simon@simonsouth.net> | 4 | ;;; Copyright © 2020 Simon South <simon@simonsouth.net> |
| 5 | ;;; Copyright © 2020 Mathieu Othacehe <m.othacehe@gmail.com> | 5 | ;;; Copyright © 2020 Mathieu Othacehe <m.othacehe@gmail.com> |
| @@ -56,6 +56,20 @@ | |||
| 56 | ;; Both return values have been encountered in the wild. | 56 | ;; Both return values have been encountered in the wild. |
| 57 | (memv (system-error-errno args) (list EPERM ENOENT))))) | 57 | (memv (system-error-errno args) (list EPERM ENOENT))))) |
| 58 | 58 | ||
| 59 | (test-assert "mounts" | ||
| 60 | ;; Check for one of the common mount points. | ||
| 61 | (let ((mounts (mounts))) | ||
| 62 | (any (match-lambda | ||
| 63 | ((point . type) | ||
| 64 | (let ((mount (find (lambda (mount) | ||
| 65 | (string=? (mount-point mount) point)) | ||
| 66 | mounts))) | ||
| 67 | (and mount | ||
| 68 | (string=? (mount-type mount) type))))) | ||
| 69 | '(("/proc" . "proc") | ||
| 70 | ("/sys" . "sysfs") | ||
| 71 | ("/dev/shm" . "tmpfs"))))) | ||
| 72 | |||
| 59 | (test-assert "mount-points" | 73 | (test-assert "mount-points" |
| 60 | ;; Reportedly "/" is not always listed as a mount point, so check a few | 74 | ;; Reportedly "/" is not always listed as a mount point, so check a few |
| 61 | ;; others (see <http://bugs.gnu.org/20261>.) | 75 | ;; others (see <http://bugs.gnu.org/20261>.) |
