summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guix/build/syscalls.scm112
-rw-r--r--tests/syscalls.scm16
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,
547and return two values: a mount bitmask (inclusive or of MS_* constants), and
548the 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
585MS_* 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
590look 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
611current 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>.)