8
8
package unix_test
9
9
10
10
import (
11
+ "bytes"
11
12
"flag"
12
13
"fmt"
13
14
"io/ioutil"
@@ -20,6 +21,7 @@ import (
20
21
"syscall"
21
22
"testing"
22
23
"time"
24
+ "unsafe"
23
25
24
26
"golang.org/x/sys/unix"
25
27
)
@@ -604,3 +606,266 @@ func chtmpdir(t *testing.T) func() {
604
606
os .RemoveAll (d )
605
607
}
606
608
}
609
+
610
+ func TestMountUnmount (t * testing.T ) {
611
+ b2s := func (arr []byte ) string {
612
+ nulli := bytes .IndexByte (arr , 0 )
613
+ if nulli == - 1 {
614
+ return string (arr )
615
+ } else {
616
+ return string (arr [:nulli ])
617
+ }
618
+ }
619
+ // use an available fs
620
+ var buffer struct {
621
+ header unix.W_Mnth
622
+ fsinfo [64 ]unix.W_Mntent
623
+ }
624
+ fsCount , err := unix .W_Getmntent_A ((* byte )(unsafe .Pointer (& buffer )), int (unsafe .Sizeof (buffer )))
625
+ if err != nil {
626
+ t .Fatalf ("W_Getmntent_A returns with error: %s" , err .Error ())
627
+ } else if fsCount == 0 {
628
+ t .Fatalf ("W_Getmntent_A returns no entries" )
629
+ }
630
+ var fs string
631
+ var fstype string
632
+ var mountpoint string
633
+ var available bool = false
634
+ for i := 0 ; i < fsCount ; i ++ {
635
+ err = unix .Unmount (b2s (buffer .fsinfo [i ].Mountpoint [:]), unix .MTM_RDWR )
636
+ if err != nil {
637
+ // Unmount and Mount require elevated privilege
638
+ // If test is run without such permission, skip test
639
+ if err == unix .EPERM {
640
+ t .Logf ("Permission denied for Unmount. Skipping test (Errno2: %X)" , unix .Errno2 ())
641
+ return
642
+ } else if err == unix .EBUSY {
643
+ continue
644
+ } else {
645
+ t .Fatalf ("Unmount returns with error: %s" , err .Error ())
646
+ }
647
+ } else {
648
+ available = true
649
+ fs = b2s (buffer .fsinfo [i ].Fsname [:])
650
+ fstype = b2s (buffer .fsinfo [i ].Fstname [:])
651
+ mountpoint = b2s (buffer .fsinfo [i ].Mountpoint [:])
652
+ t .Logf ("using file system = %s; fstype = %s and mountpoint = %s\n " , fs , fstype , mountpoint )
653
+ break
654
+ }
655
+ }
656
+ if ! available {
657
+ t .Fatalf ("No filesystem available" )
658
+ }
659
+ // test unmount
660
+ buffer .header = unix.W_Mnth {}
661
+ fsCount , err = unix .W_Getmntent_A ((* byte )(unsafe .Pointer (& buffer )), int (unsafe .Sizeof (buffer )))
662
+ if err != nil {
663
+ t .Fatalf ("W_Getmntent_A returns with error: %s" , err .Error ())
664
+ }
665
+ for i := 0 ; i < fsCount ; i ++ {
666
+ if b2s (buffer .fsinfo [i ].Fsname [:]) == fs {
667
+ t .Fatalf ("File system found after unmount" )
668
+ }
669
+ }
670
+ // test mount
671
+ err = unix .Mount (fs , mountpoint , fstype , unix .MTM_RDWR , "" )
672
+ if err != nil {
673
+ t .Fatalf ("Mount returns with error: %s" , err .Error ())
674
+ }
675
+ buffer .header = unix.W_Mnth {}
676
+ fsCount , err = unix .W_Getmntent_A ((* byte )(unsafe .Pointer (& buffer )), int (unsafe .Sizeof (buffer )))
677
+ if err != nil {
678
+ t .Fatalf ("W_Getmntent_A returns with error: %s" , err .Error ())
679
+ }
680
+ fsMounted := false
681
+ for i := 0 ; i < fsCount ; i ++ {
682
+ if b2s (buffer .fsinfo [i ].Fsname [:]) == fs && b2s (buffer .fsinfo [i ].Mountpoint [:]) == mountpoint {
683
+ fsMounted = true
684
+ }
685
+ }
686
+ if ! fsMounted {
687
+ t .Fatalf ("%s not mounted after Mount()" , fs )
688
+ }
689
+ }
690
+
691
+ func TestChroot (t * testing.T ) {
692
+ // create temp dir and tempfile 1
693
+ tempDir , err := ioutil .TempDir ("" , "TestChroot" )
694
+ if err != nil {
695
+ t .Fatalf ("TempDir: %s" , err .Error ())
696
+ }
697
+ defer os .RemoveAll (tempDir )
698
+ f , err := ioutil .TempFile (tempDir , "chroot_test_file" )
699
+ if err != nil {
700
+ t .Fatalf ("TempFile: %s" , err .Error ())
701
+ }
702
+ // chroot temp dir
703
+ err = unix .Chroot (tempDir )
704
+ // Chroot requires elevated privilege
705
+ // If test is run without such permission, skip test
706
+ if err == unix .EPERM {
707
+ t .Logf ("Denied permission for Chroot. Skipping test (Errno2: %X)" , unix .Errno2 ())
708
+ return
709
+ } else if err != nil {
710
+ t .Fatalf ("Chroot: %s" , err .Error ())
711
+ }
712
+ // check if tempDir contains test file
713
+ files , err := ioutil .ReadDir ("/" )
714
+ if err != nil {
715
+ t .Fatalf ("ReadDir: %s" , err .Error ())
716
+ }
717
+ found := false
718
+ for _ , file := range files {
719
+ if file .Name () == filepath .Base (f .Name ()) {
720
+ found = true
721
+ break
722
+ }
723
+ }
724
+ if ! found {
725
+ t .Fatalf ("Temp file not found in temp dir" )
726
+ }
727
+ }
728
+
729
+ func TestFlock (t * testing.T ) {
730
+ if os .Getenv ("GO_WANT_HELPER_PROCESS" ) == "1" {
731
+ defer os .Exit (0 )
732
+ if len (os .Args ) != 3 {
733
+ fmt .Printf ("bad argument" )
734
+ return
735
+ }
736
+ fn := os .Args [2 ]
737
+ f , err := os .OpenFile (fn , os .O_RDWR , 0755 )
738
+ if err != nil {
739
+ fmt .Printf ("%s" , err .Error ())
740
+ return
741
+ }
742
+ err = unix .Flock (int (f .Fd ()), unix .LOCK_EX | unix .LOCK_NB )
743
+ // if the lock we are trying should be locked, ignore EAGAIN error
744
+ // otherwise, report all errors
745
+ if err != nil && err != unix .EAGAIN {
746
+ fmt .Printf ("%s" , err .Error ())
747
+ }
748
+ } else {
749
+ // create temp dir and tempfile 1
750
+ tempDir , err := ioutil .TempDir ("" , "TestFlock" )
751
+ if err != nil {
752
+ t .Fatalf ("TempDir: %s" , err .Error ())
753
+ }
754
+ defer os .RemoveAll (tempDir )
755
+ f , err := ioutil .TempFile (tempDir , "flock_test_file" )
756
+ if err != nil {
757
+ t .Fatalf ("TempFile: %s" , err .Error ())
758
+ }
759
+ fd := int (f .Fd ())
760
+
761
+ /* Test Case 1
762
+ * Try acquiring an occupied lock from another process
763
+ */
764
+ err = unix .Flock (fd , unix .LOCK_EX )
765
+ if err != nil {
766
+ t .Fatalf ("Flock: %s" , err .Error ())
767
+ }
768
+ cmd := exec .Command (os .Args [0 ], "-test.run=TestFlock" , f .Name ())
769
+ cmd .Env = append (os .Environ (), "GO_WANT_HELPER_PROCESS=1" )
770
+ out , err := cmd .CombinedOutput ()
771
+ if len (out ) > 0 || err != nil {
772
+ t .Fatalf ("child process: %q, %v" , out , err )
773
+ }
774
+ err = unix .Flock (fd , unix .LOCK_UN )
775
+ if err != nil {
776
+ t .Fatalf ("Flock: %s" , err .Error ())
777
+ }
778
+
779
+ /* Test Case 2
780
+ * Try locking with Flock and FcntlFlock for same file
781
+ */
782
+ err = unix .Flock (fd , unix .LOCK_EX )
783
+ if err != nil {
784
+ t .Fatalf ("Flock: %s" , err .Error ())
785
+ }
786
+ flock := unix.Flock_t {
787
+ Type : int16 (unix .F_WRLCK ),
788
+ Whence : int16 (0 ),
789
+ Start : int64 (0 ),
790
+ Len : int64 (0 ),
791
+ Pid : int32 (unix .Getppid ()),
792
+ }
793
+ err = unix .FcntlFlock (f .Fd (), unix .F_SETLK , & flock )
794
+ if err != nil {
795
+ t .Fatalf ("FcntlFlock: %s" , err .Error ())
796
+ }
797
+ }
798
+ }
799
+
800
+ func TestSelect (t * testing.T ) {
801
+ for {
802
+ n , err := unix .Select (0 , nil , nil , nil , & unix.Timeval {Sec : 0 , Usec : 0 })
803
+ if err == unix .EINTR {
804
+ t .Logf ("Select interrupted" )
805
+ continue
806
+ } else if err != nil {
807
+ t .Fatalf ("Select: %v" , err )
808
+ }
809
+ if n != 0 {
810
+ t .Fatalf ("Select: got %v ready file descriptors, expected 0" , n )
811
+ }
812
+ break
813
+ }
814
+
815
+ dur := 250 * time .Millisecond
816
+ var took time.Duration
817
+ for {
818
+ // On some platforms (e.g. Linux), the passed-in timeval is
819
+ // updated by select(2). Make sure to reset to the full duration
820
+ // in case of an EINTR.
821
+ tv := unix .NsecToTimeval (int64 (dur ))
822
+ start := time .Now ()
823
+ n , err := unix .Select (0 , nil , nil , nil , & tv )
824
+ took = time .Since (start )
825
+ if err == unix .EINTR {
826
+ t .Logf ("Select interrupted after %v" , took )
827
+ continue
828
+ } else if err != nil {
829
+ t .Fatalf ("Select: %v" , err )
830
+ }
831
+ if n != 0 {
832
+ t .Fatalf ("Select: got %v ready file descriptors, expected 0" , n )
833
+ }
834
+ break
835
+ }
836
+
837
+ // On some BSDs the actual timeout might also be slightly less than the requested.
838
+ // Add an acceptable margin to avoid flaky tests.
839
+ if took < dur * 2 / 3 {
840
+ t .Errorf ("Select: got %v timeout, expected at least %v" , took , dur )
841
+ }
842
+
843
+ rr , ww , err := os .Pipe ()
844
+ if err != nil {
845
+ t .Fatal (err )
846
+ }
847
+ defer rr .Close ()
848
+ defer ww .Close ()
849
+
850
+ if _ , err := ww .Write ([]byte ("HELLO GOPHER" )); err != nil {
851
+ t .Fatal (err )
852
+ }
853
+
854
+ rFdSet := & unix.FdSet {}
855
+ fd := int (rr .Fd ())
856
+ rFdSet .Set (fd )
857
+
858
+ for {
859
+ n , err := unix .Select (fd + 1 , rFdSet , nil , nil , nil )
860
+ if err == unix .EINTR {
861
+ t .Log ("Select interrupted" )
862
+ continue
863
+ } else if err != nil {
864
+ t .Fatalf ("Select: %v" , err )
865
+ }
866
+ if n != 1 {
867
+ t .Fatalf ("Select: got %v ready file descriptors, expected 1" , n )
868
+ }
869
+ break
870
+ }
871
+ }
0 commit comments